xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/m16c/order.c (revision 17d96ee84f26c023336d9d73350c62eb542d5b4c)
1 /*	Id: order.c,v 1.22 2014/06/01 11:35:02 ragge Exp 	*/
2 /*	$NetBSD: order.c,v 1.1.1.4 2014/07/24 19:17:52 plunky Exp $	*/
3 /*
4  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 
31 # include "pass2.h"
32 # include <strings.h>
33 
34 int canaddr(NODE *);
35 
36 /*
37  * should the assignment op p be stored,
38  * given that it lies as the right operand of o
39  * (or the left, if o==UNARY MUL)
40  */
41 /*
42 void
43 stoasg(NODE *p, int o)
44 {
45 	if (x2debug)
46 		printf("stoasg(%p, %o)\n", p, o);
47 }
48 */
49 /* should we delay the INCR or DECR operation p */
50 int
deltest(NODE * p)51 deltest(NODE *p)
52 {
53 	return 0;
54 }
55 
56 /*
57  * Check if p can be autoincremented.
58  * XXX - nothing can be autoincremented for now.
59  */
60 int
autoincr(NODE * p)61 autoincr(NODE *p)
62 {
63 	return 0;
64 }
65 
66 /* is it legal to make an OREG or NAME entry which has an
67  * offset of off, (from a register of r), if the
68  * resulting thing had type t */
69 int
notoff(TWORD t,int r,CONSZ off,char * cp)70 notoff(TWORD t, int r, CONSZ off, char *cp)
71 {
72 	return(0);  /* YES */
73 }
74 
75 /*
76  * Turn a UMUL-referenced node into OREG.
77  */
78 int
offstar(NODE * p,int shape)79 offstar(NODE *p, int shape)
80 {
81 	if (x2debug)
82 		printf("offstar(%p)\n", p);
83 
84 	if( p->n_op == PLUS || p->n_op == MINUS ){
85 		if( p->n_right->n_op == ICON ){
86 			geninsn(p->n_left, INBREG);
87 			p->n_su = -1;
88 			return 1;
89 		}
90 	}
91 	geninsn(p, INBREG);
92 	return 0;
93 }
94 
95 /*
96  * Shape matches for UMUL.  Cooperates with offstar().
97  */
98 int
shumul(NODE * p,int shape)99 shumul(NODE *p, int shape)
100 {
101 //	NODE *l = p->n_left;
102 
103 #ifdef PCC_DEBUG
104 	if (x2debug) {
105 		printf("shumul(%p)\n", p);
106 		fwalk(p, e2print, 0);
107 	}
108 #endif
109 	/* XXX - fix */
110 
111 	/* Can only generate OREG of BREGs (or FB) */
112 	if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB))
113 		return SROREG;
114 #if 0
115 	if ((p->n_op == PLUS || p->n_op == MINUS) &&
116 	    (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) &&
117 	    p->n_right->n_op == ICON)
118 		return SOREG;
119 	return 0;
120 #else
121 	return SROREG;
122 #endif
123 }
124 
125 /*
126  * Rewrite increment/decrement operation.
127  */
128 int
setincr(NODE * p)129 setincr(NODE *p)
130 {
131 	if (x2debug)
132 		printf("setincr(%p)\n", p);
133 
134 	return(0);
135 }
136 
137 /*
138  * Rewrite operations on binary operators (like +, -, etc...).
139  * Called as a result of table lookup.
140  */
141 int
setbin(NODE * p)142 setbin(NODE *p)
143 {
144 
145 	if (x2debug)
146 		printf("setbin(%p)\n", p);
147 	return 0;
148 
149 }
150 
151 /* setup for assignment operator */
152 int
setasg(NODE * p,int cookie)153 setasg(NODE *p, int cookie)
154 {
155 	if (x2debug)
156 		printf("setasg(%p)\n", p);
157 	return(0);
158 }
159 
160 /* setup for unary operator */
161 int
setuni(NODE * p,int cookie)162 setuni(NODE *p, int cookie)
163 {
164 	return 0;
165 }
166 
167 #if 0
168 /*
169  * register allocation for instructions with special preferences.
170  */
171 regcode
172 regalloc(NODE *p, struct optab *q, int wantreg)
173 {
174 	regcode regc;
175 
176 	if (q->op == DIV || q->op == MOD) {
177 		/*
178 		 * 16-bit div.
179 		 */
180 		if (regblk[R0] & 1 || regblk[R2] & 1)
181 			comperr("regalloc: needed regs inuse, node %p", p);
182 		if (p->n_su & DORIGHT) {
183 			regc = alloregs(p->n_right, A0);
184 			if (REGNUM(regc) != A0) {
185 				p->n_right = movenode(p->n_right, A0);
186 				if ((p->n_su & RMASK) == ROREG) {
187 					p->n_su &= ~RMASK;
188 					p->n_su |= RREG;
189 					p->n_right->n_su &= ~LMASK;
190 					p->n_right->n_su |= LOREG;
191 				}
192 				freeregs(regc);
193 				regblk[A0] |= 1;
194 			}
195 		}
196 		regc = alloregs(p->n_left, R0);
197 		if (REGNUM(regc) != R0) {
198 			p->n_left = movenode(p->n_left, R0);
199 			freeregs(regc);
200 			regblk[R0] |= 1;
201 		}
202 		if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) {
203 			regc = alloregs(p->n_right, A0);
204 			if (REGNUM(regc) != A0) {
205 				p->n_right = movenode(p->n_right, A0);
206 				if ((p->n_su & RMASK) == ROREG) {
207 					p->n_su &= ~RMASK;
208 					p->n_su |= RREG;
209 					p->n_right->n_su &= ~LMASK;
210 					p->n_right->n_su |= LOREG;
211 				}
212 			}
213 		}
214 		regblk[A0] &= ~1;
215 		regblk[R0] &= ~1;
216 		regblk[R2] &= ~1;
217 		if (q->op == DIV) {
218 			MKREGC(regc, R0, 1);
219 			regblk[R0] |= 1;
220 		} else {
221 			MKREGC(regc, R2, 1);
222 			regblk[R2] |= 1;
223 		}
224 	} else
225 		comperr("regalloc");
226 	p->n_rall = REGNUM(regc);
227 	return regc;
228 }
229 #endif
230 
231 /*
232  * Special handling of some instruction register allocation.
233  * - left is the register that left node wants.
234  * - right is the register that right node wants.
235  * - res is in which register the result will end up.
236  * - mask is registers that will be clobbered.
237  *
238  *  XXX - Fix this function
239  */
240 struct rspecial *
nspecial(struct optab * q)241 nspecial(struct optab *q)
242 {
243     switch (q->op) {
244 
245     case DIV:
246     case MOD:
247 	if(q->ltype & (TINT|TSHORT)){
248 	    static struct rspecial s[] = {
249 		{ NRES, R0 }, { NRES, R2}, { 0 } };
250 	    return s;
251 	}
252 	/*
253 	else if(q->ltype & TCHAR) {
254 	    static struct rspecial s[] = {
255 		{ NRES, R0L }, { NRES, R0H}, { 0 } };
256 	    return s;
257 	    }*/
258 	break;
259 
260     case MUL:
261 	/*
262 	if(q->ltype & (TINT|TSHORT)){
263 	    static struct rspecial s[] = {
264 		{ NRES, R0 }, { NRES, R2}, { 0 } };
265 	    return s;
266 	    }*/
267 	comperr("multiplication not implemented");
268 	break;
269 
270     default:
271 	break;
272     }
273     comperr("nspecial entry %d", q - table);
274     return 0; /* XXX gcc */
275 }
276 
277 
278 /*
279  * Splitup a function call and give away its arguments first.
280  * Calling convention used ("normal" in IAR syntax) is:
281  * - 1-byte parameters in R0L if possible, otherwise in R0H.
282  * - 2-byte pointers in A0.
283  * - 2-byte non-pointers in R0 if no byte-size arguments are found in
284  *   in the first 6 bytes of parameters, otherwise R2 or at last A0.
285  * - 4-byte parameters in R2R0.
286  */
287 void
gencall(NODE * p,NODE * prev)288 gencall(NODE *p, NODE *prev)
289 {
290 	NODE *n = 0; /* XXX gcc */
291 	static int storearg(NODE *);
292 	int o = p->n_op;
293 	int ty = optype(o);
294 
295 	if (ty == LTYPE)
296 		return;
297 
298 	switch (o) {
299 	case CALL:
300 		/* swap arguments on some hardop-converted insns */
301 		/* Normal call, just push args and be done with it */
302 		p->n_op = UCALL;
303 //printf("call\n");
304 		/* Check if left can be evaluated directly */
305 		if (p->n_left->n_op == UMUL) {
306 			TWORD t = p->n_left->n_type;
307 			int k = (freetemp(szty(t)));
308 			NODE *n = mklnode(OREG, k, FB, t);
309 			NODE *q = tcopy(n);
310 			pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t)));
311 			p->n_left = q;
312 		}
313 		gencall(p->n_left, p);
314 		p->n_rval = storearg(p->n_right);
315 //printf("end call\n");
316 		break;
317 
318 	case UFORTCALL:
319 	case FORTCALL:
320 		comperr("FORTCALL");
321 
322 	case USTCALL:
323 	case STCALL:
324 		/*
325 		 * Structure return.  Look at the node above
326 		 * to decide about buffer address:
327 		 * - FUNARG, allocate space on stack, don't remove.
328 		 * - nothing, allocate space on stack and remove.
329 		 * - STASG, get the address of the left side as arg.
330 		 * - FORCE, this ends up in a return, get supplied addr.
331 		 * (this is not pretty, but what to do?)
332 		 */
333 		if (prev == NULL || prev->n_op == FUNARG) {
334 			/* Create nodes to generate stack space */
335 			n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT),
336 			    mkbinode(MINUS, mklnode(REG, 0, STKREG, INT),
337 			    mklnode(ICON, p->n_stsize, 0, INT), INT), INT);
338 //printf("stsize %d\n", p->n_stsize);
339 			pass2_compile(ipnode(n));
340 		} else if (prev->n_op == STASG) {
341 			n = prev->n_left;
342 			if (n->n_op == UMUL)
343 				n = nfree(n);
344 			else if (n->n_op == NAME) {
345 				n->n_op = ICON; /* Constant reference */
346 				n->n_type = INCREF(n->n_type);
347 			} else
348 				comperr("gencall stasg");
349 		} else if (prev->n_op == FORCE) {
350 			; /* do nothing here */
351 		} else {
352 			comperr("gencall bad op %d", prev->n_op);
353 		}
354 
355 		/* Deal with standard arguments */
356 		gencall(p->n_left, p);
357 		if (o == STCALL) {
358 			p->n_op = USTCALL;
359 			p->n_rval = storearg(p->n_right);
360 		} else
361 			p->n_rval = 0;
362 		/* push return struct address */
363 		if (prev == NULL || prev->n_op == FUNARG) {
364 			n = mklnode(REG, 0, STKREG, INT);
365 			if (p->n_rval)
366 				n = mkbinode(PLUS, n,
367 				    mklnode(ICON, p->n_rval, 0, INT), INT);
368 			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
369 			if (prev == NULL)
370 				p->n_rval += p->n_stsize/4;
371 		} else if (prev->n_op == FORCE) {
372 			/* return value for this function */
373 			n = mklnode(OREG, 8, FPREG, INT);
374 			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
375 			p->n_rval++;
376 		} else {
377 			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
378 			n = p;
379 			*prev = *p;
380 			nfree(n);
381 		}
382 //printf("end stcall\n");
383 		break;
384 
385 	default:
386 		if (ty != UTYPE)
387 			gencall(p->n_right, p);
388 		gencall(p->n_left, p);
389 		break;
390 	}
391 }
392 
393 /*
394  * Create separate node trees for function arguments.
395  * This is partly ticky, the strange calling convention
396  * may cause a bunch of code reorganization here.
397  */
398 static int
storearg(NODE * p)399 storearg(NODE *p)
400 {
401 	NODE *n, *q, **narry;
402 	int nch, k, i, nn, rary[4];
403 	int r0l, r0h, r2, a0, stk, sz;
404 	TWORD t;
405 	int maxrargs = 0;
406 
407 	if (p->n_op == CM)
408 		maxrargs = p->n_stalign;
409 
410 	/* count the arguments */
411 	for (i = 1, q = p; q->n_op == CM; q = q->n_left)
412 		i++;
413 	nn = i;
414 
415 	/* allocate array to store arguments */
416 	narry = tmpalloc(sizeof(NODE *)*nn);
417 
418 	/* enter nodes into array */
419 	for (q = p; q->n_op == CM; q = q->n_left)
420 		narry[--i] = q->n_right;
421 	narry[--i] = q;
422 
423 	/* free CM nodes */
424 	for (q = p; q->n_op == CM; ) {
425 		n = q->n_left;
426 		nfree(q);
427 		q = n;
428 	}
429 
430 	/* count char args */
431 	r0l = r0h = r2 = a0 = 0;
432 	for (sz = nch = i = 0; i < nn && i < 6; i++) {
433 		TWORD t = narry[i]->n_type;
434 		if (sz >= 6)
435 			break;
436 		if (t == CHAR || t == UCHAR) {
437 			nch++;
438 			sz++;
439 		} else if ((t >= SHORT && t <= UNSIGNED) ||
440 		    t > BTMASK || t == FLOAT) {
441 			sz += 2;
442 		} else /* long, double */
443 			sz += 4;
444 
445 	}
446 
447 	/*
448 	 * Now the tricky part. The parameters that should be on stack
449 	 * must be found and pushed first, then the register parameters.
450 	 * For the latter, be sure that evaluating them do not use any
451 	 * registers where argument values already are inserted.
452 	 * XXX - function pointers?
453 	 * XXX foo(long a, char b) ???
454 	 */
455 	for (stk = 0; stk < 4; stk++) {
456 		TWORD t;
457 
458 		if (stk == nn)
459 			break;
460 		t = narry[stk]->n_type;
461 		if (ISFTN(DECREF(t)))
462 			t = LONG;
463 		switch (t) {
464 		case CHAR: case UCHAR:
465 			if (r0l) {
466 				if (r0h)
467 					break;
468 				rary[stk] = R2; /* char talk for 'R0H' */
469 				r0h = 1;
470 			} else {
471 				rary[stk] = R0;
472 				r0l = 1;
473 			}
474 			continue;
475 
476 		case INT: case UNSIGNED:
477 			if (r0l || nch) {
478 				if (r2) {
479 					if (a0)
480 						break;
481 					rary[stk] = A0;
482 					a0 = 1;
483 				} else {
484 					rary[stk] = R2;
485 					r2 = 1;
486 				}
487 			} else {
488 				rary[stk] = R0;
489 				r0l = r0h = 1;
490 			}
491 			continue;
492 
493 		case LONG: case ULONG:
494 			if (r0l || r2)
495 				break;
496 			rary[stk] = R0;
497 			r0l = r0h = r2 = 1;
498 			continue;
499 
500 		default:
501 			if (ISPTR(narry[stk]->n_type) &&
502 			    !ISFTN(DECREF(narry[stk]->n_type))) {
503 				if (a0) {
504 					if (r0l || nch) {
505 						if (r2)
506 							break;
507 						rary[stk] = R2;
508 						r2 = 1;
509 					} else {
510 						rary[stk] = R0;
511 						r0l = r0h = 1;
512 					}
513 				} else {
514 					rary[stk] = A0;
515 					a0 = 1;
516 				}
517 				continue;
518 			}
519 			break;
520 		}
521 		break;
522 	}
523 
524 	/*
525 	 * The arguments that must be on stack are stk->nn args.
526 	 * Argument 0->stk-1 should be put in the rary[] register.
527 	 */
528 	for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */
529 		NODE nod;
530 		pass2_compile(ipnode(mkunode(FUNARG,
531 		    narry[i], 0, narry[i]->n_type)));
532 		nod.n_type = narry[i]->n_type;
533 		sz += tlen(&nod);
534 	}
535 	/* if param cannot be addressed directly, evaluate and put on stack */
536 	for (i = 0; i < stk; i++) {
537 
538 		if (canaddr(narry[i]))
539 			continue;
540 		t = narry[i]->n_type;
541 		k = (freetemp(szty(t)));
542 		n = mklnode(OREG, k, FB, t);
543 		q = tcopy(n);
544 		pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t)));
545 		narry[i] = q;
546 	}
547 	/* move args to registers */
548 	for (i = 0; i < stk; i++) {
549 		t = narry[i]->n_type;
550 		pass2_compile(ipnode(mkbinode(ASSIGN,
551 		    mklnode(REG, 0, rary[i], t), narry[i], t)));
552 	}
553 	return sz;
554 }
555 
556 /*
557  * Tell if a register can hold a specific datatype.
558  */
559 #if 0
560 int
561 mayuse(int reg, TWORD type)
562 {
563 	return 1;  /* Everything is OK */
564 }
565 #endif
566 
567 #ifdef TAILCALL
568 void
mktailopt(struct interpass * ip1,struct interpass * ip2)569 mktailopt(struct interpass *ip1, struct interpass *ip2)
570 {
571 	extern int earlylab;
572 	extern char *cftname;
573 	char *fn;
574 	NODE *p;
575 
576 	p = ip1->ip_node->n_left->n_left;
577 	if (p->n_op == ICON) {
578 		fn = p->n_name;
579 		/* calling ourselves */
580 		p = ip1->ip_node->n_left;
581 		if (p->n_op == CALL) {
582 			if (storearg(p->n_right))
583 				comperr("too many args: fix mktailopt");
584 			p->n_op = UCALL;
585 		}
586 		tfree(ip1->ip_node);
587 		p = ip2->ip_node->n_left;
588 		if (strcmp(fn, cftname)) {
589 			/* Not us, must generate fake prologue */
590 			ip1->type = IP_ASM;
591 			ip1->ip_asm = "\tmov.w FB,SP\n\tpop.w FB\n";
592 			pass2_compile(ip1);
593 			p->n_lval = p->n_rval = 0;
594 			p->n_name = fn;
595 		} else
596 			p->n_lval = earlylab;
597 	} else {
598 		pass2_compile(ip1);
599 	}
600 	pass2_compile(ip2);
601 }
602 #endif
603 /*
604  * Set registers "live" at function calls (like arguments in registers).
605  * This is for liveness analysis of registers.
606  */
607 int *
livecall(NODE * p)608 livecall(NODE *p)
609 {
610 	static int r[1] = { -1 }; /* Terminate with -1 */
611 
612 	return &r[0];
613 }
614 
615 /*
616  * Signal whether the instruction is acceptable for this target.
617  */
618 int
acceptable(struct optab * op)619 acceptable(struct optab *op)
620 {
621 	return 1;
622 }
623