xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/amd64/order.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
1 /*	Id: order.c,v 1.18 2015/12/13 09:00:04 ragge Exp 	*/
2 /*	$NetBSD: order.c,v 1.1.1.5 2016/02/09 20:28:10 plunky Exp $	*/
3 /*
4  * Copyright (c) 2008 Michael Shalayeff
5  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 # include "pass2.h"
33 
34 #include <string.h>
35 
36 int canaddr(NODE *);
37 
38 /* is it legal to make an OREG or NAME entry which has an
39  * offset of off, (from a register of r), if the
40  * resulting thing had type t */
41 int
notoff(TWORD t,int r,CONSZ off,char * cp)42 notoff(TWORD t, int r, CONSZ off, char *cp)
43 {
44 	if (off > MAX_INT || off < MIN_INT)
45 		return 1; /* max signed 32-bit offset */
46 	return(0);  /* YES */
47 }
48 
49 /*
50  * Check if LS and try to make it indexable.
51  * Ignore SCONV to long.
52  * Return 0 if failed.
53  */
54 static int
findls(NODE * p,int check)55 findls(NODE *p, int check)
56 {
57 	CONSZ c;
58 
59 	if (p->n_op == SCONV && p->n_type == LONG && p->n_left->n_type == INT)
60 		p = p->n_left; /* Ignore pointless SCONVs here */
61 	if (p->n_op != LS || p->n_right->n_op != ICON)
62 		return 0;
63 	if ((c = getlval(p->n_right)) != 1 && c != 2 && c != 3)
64 		return 0;
65 	if (check == 1 && p->n_left->n_op != REG)
66 		return 0;
67 	if (!isreg(p->n_left))
68 		(void)geninsn(p->n_left, INAREG);
69 	return 1;
70 }
71 
72 /*
73  * Turn a UMUL-referenced node into OREG.
74  * Be careful about register classes, this is a place where classes change.
75  *
76  * AMD64 (and i386) have a quite powerful addressing scheme:
77  * 	:	4(%rax)		4 + %rax
78  * 	:	4(%rbx,%rax,8)	4 + %rbx + %rax * 8
79  * 	:	4(,%rax)	4 + %rax * 8
80  * The 8 above can be 1,2,4 or 8.
81  */
82 void
offstar(NODE * p,int shape)83 offstar(NODE *p, int shape)
84 {
85 	NODE *l;
86 
87 	if (x2debug) {
88 		printf("offstar(%p)\n", p);
89 		fwalk(p, e2print, 0);
90 	}
91 
92 	if (isreg(p))
93 		return; /* Matched (%rax) */
94 
95 	if (findls(p, 0))
96 		return; /* Matched (,%rax,8) */
97 
98 	if ((p->n_op == PLUS || p->n_op == MINUS) &&
99 	    p->n_left->n_op == ICON &&
100 	    p->n_left->n_name[0] == '\0' &&
101 	    notoff(0, 0,  getlval(p->n_left), 0) == 0) {
102 		l = p->n_right;
103 		if (isreg(l))
104 			return; /* Matched 4(%rax) */
105 		if (findls(l, 0))
106 			return; /* Matched 4(,%rax,8) */
107 		if (l->n_op == PLUS && isreg(l->n_right)) {
108 			if (findls(l->n_left, 0))
109 				return; /* Matched 4(%rbx,%rax,8) */
110 			(void)geninsn(l->n_left, INAREG);
111 			return; /* Generate 4(%rbx,%rax) */
112 		}
113 		(void)geninsn(l, INAREG);
114 		return; /* Generate 4(%rbx) */
115 	}
116 
117 	if (p->n_op == PLUS) {
118 		if (!isreg(p->n_left)) /* ensure right is REG */
119 			(void)geninsn(p->n_left, INAREG);
120 		if (isreg(p->n_right))
121 			return; /* Matched (%rax,%rbx) */
122 		if (findls(p->n_right, 0))
123 			return; /* Matched (%rax,%rbx,4) */
124 		(void)geninsn(p->n_right, INAREG);
125 		return; /* Generate (%rbx,%rax) */
126 	}
127 
128 	(void)geninsn(p, INAREG);
129 }
130 
131 /*
132  * Do the actual conversion of offstar-found OREGs into real OREGs.
133  * For simple OREGs conversion should already be done.
134  */
135 void
myormake(NODE * q)136 myormake(NODE *q)
137 {
138 	static int shtbl[] = { 1,2,4,8 };
139 	NODE *p, *r;
140 	CONSZ c = 0;
141 	int r1, r2, sh;
142 	int mkconv = 0;
143 	char *n = "";
144 
145 #define	risreg(p)	(p->n_op == REG)
146 	if (x2debug) {
147 		printf("myormake(%p)\n", q);
148 		fwalk(q, e2print, 0);
149 	}
150 	r1 = r2 = MAXREGS;
151 	sh = 1;
152 
153 	r = p = q->n_left;
154 
155 	if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_left->n_op == ICON) {
156 		c = getlval(p->n_left);
157 		n = p->n_left->n_name;
158 		p = p->n_right;
159 	}
160 
161 	if (p->n_op == PLUS && risreg(p->n_left)) {
162 		r1 = regno(p->n_left);
163 		p = p->n_right;
164 	}
165 
166 	if (findls(p, 1)) {
167 		if (p->n_op == SCONV)
168 			p = p->n_left;
169 		sh = shtbl[(int)getlval(p->n_right)];
170 		r2 = regno(p->n_left);
171 		mkconv = 1;
172 	} else if (risreg(p)) {
173 		r2 = regno(p);
174 		mkconv = 1;
175 	} //else
176 	//	comperr("bad myormake tree");
177 
178 	if (mkconv == 0)
179 		return;
180 
181 	q->n_op = OREG;
182 	setlval(q, c);
183 	q->n_rval = R2PACK(r1, r2, sh);
184 	q->n_name = n;
185 	tfree(r);
186 	if (x2debug) {
187 		printf("myormake converted %p\n", q);
188 		fwalk(q, e2print, 0);
189 	}
190 }
191 
192 /*
193  * Shape matches for UMUL.  Cooperates with offstar().
194  */
195 int
shumul(NODE * p,int shape)196 shumul(NODE *p, int shape)
197 {
198 
199 	if (x2debug)
200 		printf("shumul(%p)\n", p);
201 
202 	/* Turns currently anything into OREG on x86 */
203 	if (shape & SOREG)
204 		return SROREG;
205 	return SRNOPE;
206 }
207 
208 /*
209  * Rewrite operations on binary operators (like +, -, etc...).
210  * Called as a result of table lookup.
211  */
212 int
setbin(NODE * p)213 setbin(NODE *p)
214 {
215 
216 	if (x2debug)
217 		printf("setbin(%p)\n", p);
218 	return 0;
219 
220 }
221 
222 /* setup for assignment operator */
223 int
setasg(NODE * p,int cookie)224 setasg(NODE *p, int cookie)
225 {
226 	if (x2debug)
227 		printf("setasg(%p)\n", p);
228 	return(0);
229 }
230 
231 /* setup for unary operator */
232 int
setuni(NODE * p,int cookie)233 setuni(NODE *p, int cookie)
234 {
235 	return 0;
236 }
237 
238 /*
239  * Special handling of some instruction register allocation.
240  */
241 struct rspecial *
nspecial(struct optab * q)242 nspecial(struct optab *q)
243 {
244 	switch (q->op) {
245 	case SCONV:
246 		if ((q->ltype & TINT) &&
247 		    q->rtype == (TLONGLONG|TULONGLONG|TLONG|TULONG)) {
248 			static struct rspecial s[] = {
249 				{ NLEFT, RAX }, { NRES, RAX }, { 0 } };
250 			return s;
251 		}
252 		break;
253 
254 	case DIV:
255 		{
256 			static struct rspecial s[] = {
257 				{ NEVER, RAX }, { NEVER, RDX },
258 				{ NLEFT, RAX }, { NRES, RAX },
259 				{ NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } };
260 			return s;
261 		}
262 		break;
263 
264 	case MOD:
265 		if (q->ltype & TUCHAR) {
266 			static struct rspecial s[] = {
267 				{ NEVER, RAX },
268 				{ NLEFT, RAX }, { NRES, RAX },
269 				{ NORIGHT, RAX }, { 0 } };
270 			return s;
271 		} else {
272 			static struct rspecial s[] = {
273 				{ NEVER, RAX }, { NEVER, RDX },
274 				{ NLEFT, RAX }, { NRES, RDX },
275 				{ NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } };
276 			return s;
277 		}
278 		break;
279 
280 	case STARG:
281 		{
282 			static struct rspecial s[] = {
283 				{ NEVER, RDI },
284 				{ NLEFT, RSI },
285 				{ NEVER, RCX }, { 0 } };
286 			return s;
287 		}
288 
289 	case STASG:
290 		{
291 			static struct rspecial s[] = {
292 				{ NEVER, RDI },
293 				{ NRIGHT, RSI }, { NOLEFT, RSI },
294 				{ NOLEFT, RCX }, { NORIGHT, RCX },
295 				{ NEVER, RCX }, { 0 } };
296 			return s;
297 		}
298 
299 	case MUL:
300 		if (q->lshape == SAREG) {
301 			static struct rspecial s[] = {
302 				{ NEVER, RAX },
303 				{ NLEFT, RAX }, { NRES, RAX }, { 0 } };
304 			return s;
305 		}
306 		break;
307 
308 	case LS:
309 	case RS:
310 		{
311 			static struct rspecial s[] = {
312 				{ NRIGHT, RCX }, { NOLEFT, RCX }, { 0 } };
313 			return s;
314 		}
315 		break;
316 
317 	default:
318 		break;
319 	}
320 	comperr("nspecial entry %d", q - table);
321 	return 0; /* XXX gcc */
322 }
323 
324 /*
325  * Set evaluation order of a binary node if it differs from default.
326  */
327 int
setorder(NODE * p)328 setorder(NODE *p)
329 {
330 	return 0; /* nothing differs on x86 */
331 }
332 
333 /*
334  * set registers in calling conventions live.
335  */
336 int *
livecall(NODE * p)337 livecall(NODE *p)
338 {
339 	static int r[NTEMPREG+1];
340 	NODE *q;
341 	int cr = 0;
342 
343 	if (optype(p->n_op) != BITYPE)
344 		return r[0] = -1, r;
345 
346 	for (q = p->n_right; q->n_op == CM; q = q->n_left) {
347 		if (q->n_right->n_op == ASSIGN &&
348 		    q->n_right->n_left->n_op == REG)
349 			r[cr++] = regno(q->n_right->n_left);
350 	}
351 	if (q->n_op == ASSIGN && q->n_left->n_op == REG)
352 		r[cr++] = regno(q->n_left);
353 	r[cr++] = -1;
354 	return r;
355 }
356 
357 /*
358  * Signal whether the instruction is acceptable for this target.
359  */
360 int
acceptable(struct optab * op)361 acceptable(struct optab *op)
362 {
363 	return 1;
364 }
365