xref: /netbsd/external/bsd/pcc/dist/pcc/arch/m16c/local2.c (revision 6550d01e)
1 /*	Id: local2.c,v 1.40 2008/11/22 16:12:24 ragge Exp 	*/
2 /*	$NetBSD: local2.c,v 1.1.1.3 2010/06/03 18:57:17 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 <ctype.h>
33 
34 void acon(NODE *p);
35 int argsize(NODE *p);
36 void genargs(NODE *p);
37 
38 static int ftlab1, ftlab2;
39 
40 void
41 deflab(int label)
42 {
43 	printf(LABFMT ":\n", label);
44 }
45 
46 static TWORD ftype;
47 static int addto;
48 
49 void
50 prologue(struct interpass_prolog *ipp)
51 {
52     ftype = ipp->ipp_type;
53 
54 #if 0
55     if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR)
56 	comperr("fix prologue register savings", ipp->ipp_regs);
57 #endif
58 
59     printf("	RSEG CODE:CODE:REORDER:NOROOT(0)\n");
60     if (ipp->ipp_vis)
61 	printf("	PUBLIC %s\n", ipp->ipp_name);
62     printf("%s:\n", ipp->ipp_name);
63 
64 #if 0
65     if (xsaveip) {
66 	/* Optimizer running, save space on stack */
67 	addto = (p2maxautooff - AUTOINIT)/SZCHAR;
68 	printf("	enter #%d\n", addto);
69     } else {
70 #endif
71 
72 	/* non-optimized code, jump to epilogue for code generation */
73 	ftlab1 = getlab2();
74 	ftlab2 = getlab2();
75 	printf("	jmp.w " LABFMT "\n", ftlab1);
76 	deflab(ftlab2);
77 }
78 
79 /*
80  * End of block.
81  */
82 void
83 eoftn(struct interpass_prolog *ipp)
84 {
85 #if 0
86 	if (ipp->ipp_regs != MINRVAR)
87 		comperr("fix eoftn register savings %x", ipp->ipp_regs);
88 #endif
89 
90 	//	if (xsaveip == 0)
91 	addto = (p2maxautooff - AUTOINIT)/SZCHAR;
92 
93 	/* return from function code */
94 	//deflab(ipp->ipp_ip.ip_lbl);   //XXX - is this necessary?
95 
96 	/* If retval is a pointer and not a function pointer, put in A0 */
97 	if (ISPTR(DECREF(ipp->ipp_type)) &&
98 	    !ISFTN(DECREF(DECREF(ipp->ipp_type))))
99 	    printf("	mov.w r0,a0\n");
100 
101 	/* struct return needs special treatment */
102 	if (ftype == STRTY || ftype == UNIONTY) {
103 		comperr("fix struct return in eoftn");
104 	} else
105 		printf("	exitd\n");
106 
107 	/* Prolog code */
108 	//	if (xsaveip == 0) {
109 		deflab(ftlab1);
110 		printf("	enter #%d\n", addto);
111 		printf("	jmp.w " LABFMT "\n", ftlab2);
112 		//}
113 }
114 
115 /*
116  * add/sub/...
117  *
118  * Param given:
119  */
120 void
121 hopcode(int f, int o)
122 {
123 	char *str;
124 
125 	switch (o) {
126 	case PLUS:
127 		str = "add";
128 		break;
129 	case MINUS:
130 		str = "sub";
131 		break;
132 	case AND:
133 		str = "and";
134 		break;
135 	case OR:
136 		str = "or";
137 		break;
138 	case ER:
139 		str = "xor";
140 		break;
141 	default:
142 		comperr("hopcode2: %d", o);
143 		str = 0; /* XXX gcc */
144 	}
145 	printf("%s.%c", str, f);
146 }
147 
148 char *
149 rnames[] = {  /* keyed to register number tokens */
150     "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l",
151     "r1h", "r1l",
152 };
153 
154 /*
155  * Return the size (in bytes) of some types.
156  */
157 int
158 tlen(p) NODE *p;
159 {
160 	switch(p->n_type) {
161 		case CHAR:
162 		case UCHAR:
163 			return(1);
164 
165 		case INT:
166 		case UNSIGNED:
167 		case FLOAT:
168 			return 2;
169 
170 		case DOUBLE:
171 		case LONG:
172 		case ULONG:
173 			return 4;
174 
175 		default:
176 			if (!ISPTR(p->n_type))
177 				comperr("tlen type %d not pointer");
178 			return SZPOINT(p->n_type)/SZCHAR;
179 		}
180 }
181 
182 /*
183  * Emit code to compare two longlong numbers.
184  */
185 static void
186 twollcomp(NODE *p)
187 {
188 	int o = p->n_op;
189 	int s = getlab2();
190 	int e = p->n_label;
191 	int cb1, cb2;
192 
193 	if (o >= ULE)
194 		o -= (ULE-LE);
195 	switch (o) {
196 	case NE:
197 		cb1 = 0;
198 		cb2 = NE;
199 		break;
200 	case EQ:
201 		cb1 = NE;
202 		cb2 = 0;
203 		break;
204 	case LE:
205 	case LT:
206 		cb1 = GT;
207 		cb2 = LT;
208 		break;
209 	case GE:
210 	case GT:
211 		cb1 = LT;
212 		cb2 = GT;
213 		break;
214 
215 	default:
216 		cb1 = cb2 = 0; /* XXX gcc */
217 	}
218 	if (p->n_op >= ULE)
219 		cb1 += 4, cb2 += 4;
220 	expand(p, 0, "	cmp.w UR,UL\n");
221 	if (cb1) cbgen(cb1, s);
222 	if (cb2) cbgen(cb2, e);
223 	expand(p, 0, "	cmp.w AR,AL\n");
224 	cbgen(p->n_op, e);
225 	deflab(s);
226 }
227 
228 
229 void
230 zzzcode(NODE *p, int c)
231 {
232 	NODE *l;
233 
234 	switch (c) {
235 	case 'A': /* print negative shift constant */
236 		p = getlr(p, 'R');
237 		if (p->n_op != ICON)
238 			comperr("ZA bad use");
239 		p->n_lval = -p->n_lval;
240 		adrput(stdout, p);
241 		p->n_lval = -p->n_lval;
242 		break;
243 
244 	case 'B':
245 		if (p->n_rval)
246 			printf("	add.b #%d,%s\n",
247 			    p->n_rval, rnames[STKREG]);
248 		break;
249 
250 	case 'C': /* Print label address */
251 		p = p->n_left;
252 		if (p->n_lval)
253 			printf(LABFMT, (int)p->n_lval);
254 		else
255 			printf("%s", p->n_name);
256 		break;
257 
258 	case 'D': /* copy function pointers */
259 		l = p->n_left;
260 		printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n",
261 		    p->n_right->n_name, rnames[l->n_rval+1],
262 		    p->n_right->n_name, rnames[l->n_rval]);
263 		break;
264 
265 	case 'E': /* double-reg printout */
266 		/* XXX - always r0r2 here */
267 		printf("%s%s", rnames[R0], rnames[R2]);
268 		break;
269 
270 	case 'F': /* long comparisions */
271 		twollcomp(p);
272 		break;
273 
274 	case 'G':
275 		printf("R0R2");
276 		break;
277 
278 	case 'H': /* push 32-bit address (for functions) */
279 		printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n",
280 		    p->n_left->n_name, p->n_left->n_name);
281 		break;
282 
283 	case 'I': /* push 32-bit address (for functions) */
284 		l = p->n_left;
285 		printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n",
286 		    (int)l->n_lval, rnames[l->n_rval],
287 		    (int)l->n_lval+2, rnames[l->n_rval]);
288 		break;
289 
290 	default:
291 		comperr("bad zzzcode %c", c);
292 	}
293 }
294 
295 /*ARGSUSED*/
296 int
297 rewfld(NODE *p)
298 {
299 	return(1);
300 }
301 
302 int canaddr(NODE *);
303 int
304 canaddr(NODE *p)
305 {
306 	int o = p->n_op;
307 
308 	if (o==NAME || o==REG || o==ICON || o==OREG ||
309 	    (o==UMUL && shumul(p->n_left, SOREG) == SRDIR))
310 		return(1);
311 	return(0);
312 }
313 
314 int
315 fldexpand(NODE *p, int cookie, char **cp)
316 {
317 	return 0;
318 }
319 
320 /*
321  * Does the bitfield shape match?
322  */
323 int
324 flshape(NODE *p)
325 {
326 	int o = p->n_op;
327 
328 	if (o == OREG || o == REG || o == NAME)
329 		return SRDIR; /* Direct match */
330 	if (o == UMUL && shumul(p->n_left, SOREG))
331 		return SROREG; /* Convert into oreg */
332 	return SRREG; /* put it into a register */
333 }
334 
335 /* INTEMP shapes must not contain any temporary registers */
336 /* XXX should this go away now? */
337 int
338 shtemp(NODE *p)
339 {
340 	return 0;
341 }
342 
343 void
344 adrcon(CONSZ val)
345 {
346 	printf("$" CONFMT, val);
347 }
348 
349 void
350 conput(FILE *fp, NODE *p)
351 {
352 	int val = p->n_lval;
353 
354 	switch (p->n_op) {
355 	case ICON:
356 		if (p->n_name[0] != '\0') {
357 			fprintf(fp, "%s", p->n_name);
358 			if (val)
359 				fprintf(fp, "+%d", val);
360 		} else
361 			fprintf(fp, "%d", val);
362 		return;
363 
364 	default:
365 		comperr("illegal conput");
366 	}
367 }
368 
369 /*ARGSUSED*/
370 void
371 insput(NODE *p)
372 {
373 	comperr("insput");
374 }
375 
376 /*
377  * Write out the upper address, like the upper register of a 2-register
378  * reference, or the next memory location.
379  */
380 void
381 upput(NODE *p, int size)
382 {
383 
384 	size /= SZINT;
385 	switch (p->n_op) {
386 	case REG:
387 		fputs(rnames[p->n_rval + 1], stdout);
388 		break;
389 
390 	case NAME:
391 	case OREG:
392 		p->n_lval += size;
393 		adrput(stdout, p);
394 		p->n_lval -= size;
395 		break;
396 	case ICON:
397 		fprintf(stdout, "#" CONFMT, p->n_lval >> 16);
398 		break;
399 	default:
400 		comperr("upput bad op %d size %d", p->n_op, size);
401 	}
402 }
403 
404 void
405 adrput(FILE *io, NODE *p)
406 {
407 	/* output an address, with offsets, from p */
408 
409 	if (p->n_op == FLD)
410 		p = p->n_left;
411 
412 	switch (p->n_op) {
413 
414 	case NAME:
415 		if (p->n_name[0] != '\0')
416 			fputs(p->n_name, io);
417 		if (p->n_lval != 0)
418 			fprintf(io, "+" CONFMT, p->n_lval);
419 		return;
420 
421 	case OREG:
422 		if (p->n_lval)
423 			fprintf(io, "%d", (int)p->n_lval);
424 		fprintf(io, "[%s]", rnames[p->n_rval]);
425 		return;
426 	case ICON:
427 		/* addressable value of the constant */
428 		fputc('#', io);
429 		conput(io, p);
430 		return;
431 
432 	case REG:
433 	    /*if (DEUNSIGN(p->n_type) == CHAR) {
434 			fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1',
435 			    (p->n_rval & 1) ? 'H' : 'L');
436 			    } else*/
437 	    fprintf(io, "%s", rnames[p->n_rval]);
438 	    return;
439 
440 	default:
441 		comperr("illegal address, op %d, node %p", p->n_op, p);
442 		return;
443 
444 	}
445 }
446 
447 static char *
448 ccbranches[] = {
449 	"jeq",		/* jumpe */
450 	"jne",		/* jumpn */
451 	"jle",		/* jumple */
452 	"jlt",		/* jumpl */
453 	"jge",		/* jumpge */
454 	"jgt",		/* jumpg */
455 	"jleu",		/* jumple (jlequ) */
456 	"jltu",		/* jumpl (jlssu) */
457 	"jgeu",		/* jumpge (jgequ) */
458 	"jgtu",		/* jumpg (jgtru) */
459 };
460 
461 
462 /*   printf conditional and unconditional branches */
463 void
464 cbgen(int o, int lab)
465 {
466 	if (o < EQ || o > UGT)
467 		comperr("bad conditional branch: %s", opst[o]);
468 	printf("	%s " LABFMT "\n", ccbranches[o-EQ], lab);
469 }
470 
471 void
472 mycanon(NODE *p)
473 {
474 }
475 
476 void
477 myoptim(struct interpass *ip)
478 {
479 }
480 
481 #if 0
482 void
483 mygenregs(NODE *p)
484 {
485 
486 	if (p->n_op == MINUS && p->n_type == DOUBLE &&
487 	    (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) {
488 		p->n_su |= DORIGHT;
489 	}
490 	/* Must walk down correct node first for logops to work */
491 	if (p->n_op != CBRANCH)
492 		return;
493 	p = p->n_left;
494 	if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG))
495 		return;
496 	p->n_su &= ~DORIGHT;
497 
498 }
499 #endif
500 
501 struct hardops hardops[] = {
502 	{ PLUS, FLOAT, "?F_ADD_L04" },
503 	{ MUL, LONG, "?L_MUL_L03" },
504 	{ MUL, ULONG, "?L_MUL_L03" },
505 	{ DIV, LONG, "?SL_DIV_L03" },
506 	{ DIV, ULONG, "?UL_DIV_L03" },
507 	{ MOD, LONG, "?SL_MOD_L03" },
508 	{ MOD, ULONG, "?UL_MOD_L03" },
509 	{ RS, LONGLONG, "__ashrdi3" },
510 	{ RS, ULONGLONG, "__lshrdi3" },
511 	{ LS, LONGLONG, "__ashldi3" },
512 	{ LS, ULONGLONG, "__ashldi3" },
513 	{ 0 },
514 };
515 
516 int
517 special(NODE *p, int shape)
518 {
519 	switch (shape) {
520 	case SFTN:
521 		if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) {
522 			if (p->n_op == NAME || p->n_op == OREG)
523 				return SRDIR;
524 			else
525 				return SRREG;
526 		}
527 		break;
528 	}
529 	return SRNOPE;
530 }
531 
532 void
533 myreader(NODE *p)
534 {
535 	NODE *q, *r, *s, *right;
536 
537 	if (optype(p->n_op) == LTYPE)
538 		return;
539 	if (optype(p->n_op) != UTYPE)
540 		myreader(p->n_right);
541 	myreader(p->n_left);
542 
543 	switch (p->n_op) {
544 	case PLUS:
545 	case MINUS:
546 		if (p->n_type != LONG && p->n_type != ULONG)
547 			break;
548 		if (p->n_right->n_op == NAME || p->n_right->n_op == OREG)
549 			break;
550 		/* Must convert right into OREG */
551 		right = p->n_right;
552 		q = mklnode(OREG, BITOOR(freetemp(szty(right->n_type))),
553 		    FPREG, right->n_type);
554 		s = mkbinode(ASSIGN, q, right, right->n_type);
555 		r = talloc();
556 		*r = *q;
557 		p->n_right = r;
558 		pass2_compile(ipnode(s));
559 		break;
560 	}
561 }
562 
563 
564 void
565 rmove(int s, int d, TWORD t)
566 {
567 	switch (t) {
568 	case CHAR:
569 	case UCHAR:
570 	    printf("	mov.b %s,%s\n", rnames[s], rnames[d]);
571 	    break;
572 	default:
573 	    printf("	mov.w %s,%s\n", rnames[s], rnames[d]);
574 	}
575 }
576 
577 /*
578  * For class c, find worst-case displacement of the number of
579  * registers in the array r[] indexed by class.
580  */
581 int
582 COLORMAP(int c, int *r)
583 {
584 	int num;
585 
586 	switch (c) {
587 	case CLASSA:
588 		num = r[CLASSA];
589 		num += r[CLASSC];
590 		return num < 4;
591 	case CLASSB:
592 		num = r[CLASSB];
593 		return num < 2;
594 	case CLASSC:
595 		num = 2*r[CLASSA];
596 		num += r[CLASSC];
597 		return num < 4;
598 	}
599 	return 0; /* XXX gcc */
600 }
601 
602 /*
603  * Return a class suitable for a specific type.
604  */
605 int
606 gclass(TWORD t)
607 {
608 	if (t == CHAR || t == UCHAR)
609 		return CLASSC;
610 
611 	if(ISPTR(t))
612 		return CLASSB;
613 
614 	return CLASSA;
615 }
616 
617 static int sizen;
618 
619 /* XXX: Fix this. */
620 static int
621 argsiz(NODE *p)
622 {
623         TWORD t = p->n_type;
624 
625         if (t < LONGLONG || t > MAXTYPES)
626                 return 4;
627         if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
628                 return 8;
629         if (t == LDOUBLE)
630                 return 12;
631         if (t == STRTY)
632                 return p->n_stsize;
633         comperr("argsiz");
634         return 0;
635 }
636 
637 /*
638  * Calculate argument sizes.
639  * XXX: Fix this.
640  */
641 void
642 lastcall(NODE *p)
643 {
644         sizen = 0;
645         for (p = p->n_right; p->n_op == CM; p = p->n_left)
646                 sizen += argsiz(p->n_right);
647         sizen += argsiz(p);
648 }
649 
650 /*
651  * Target-dependent command-line options.
652  */
653 void
654 mflags(char *str)
655 {
656 }
657 /*
658  * Do something target-dependent for xasm arguments.
659  * Supposed to find target-specific constraints and rewrite them.
660  */
661 int
662 myxasm(struct interpass *ip, NODE *p)
663 {
664 	return 0;
665 }
666