xref: /netbsd/external/bsd/pcc/dist/pcc/arch/nova/local.c (revision 6550d01e)
1 /*	Id: local.c,v 1.7 2008/12/14 21:16:58 ragge Exp 	*/
2 /*	$NetBSD: local.c,v 1.1.1.3 2010/06/03 18:57:20 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 "pass1.h"
32 
33 /*	this file contains code which is dependent on the target machine */
34 
35 NODE *
36 clocal(NODE *p)
37 {
38 	struct symtab *q;
39 	NODE *r, *l;
40 	int o;
41 
42 	switch( o = p->n_op ){
43 	case NAME:
44 		/* handle variables */
45 		if ((q = p->n_sp) == NULL)
46 			return p; /* Nothing to care about */
47 		switch (q->sclass) {
48 		case AUTO:
49 			/* fake up a structure reference */
50 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
51 			r->n_lval = 0;
52 			r->n_rval = FPREG;
53 			p = stref(block(STREF, r, p, 0, 0, 0));
54 			break;
55 		default:
56 			break;
57 		}
58 		break;
59 
60 	case PMCONV:
61 	case PVCONV:
62                 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
63                 nfree(p);
64                 return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
65 
66 	case PCONV:
67 		l = p->n_left;
68 		/* if conversion to another pointer type, just remove */
69 		if (p->n_type > BTMASK && l->n_type > BTMASK)
70 			goto delp;
71 		break;
72 
73 	delp:	l->n_type = p->n_type;
74 		l->n_qual = p->n_qual;
75 		l->n_df = p->n_df;
76 		l->n_sue = p->n_sue;
77 		nfree(p);
78 		p = l;
79 		break;
80 	}
81 
82 #if 0
83 	register struct symtab *q;
84 	register NODE *r, *l;
85 	register int o;
86 	register int m;
87 	TWORD t;
88 
89 //printf("in:\n");
90 //fwalk(p, eprint, 0);
91 	switch( o = p->n_op ){
92 
93 	case NAME:
94 		if ((q = p->n_sp) == NULL)
95 			return p; /* Nothing to care about */
96 
97 		switch (q->sclass) {
98 
99 		case PARAM:
100 		case AUTO:
101 			/* fake up a structure reference */
102 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
103 			r->n_lval = 0;
104 			r->n_rval = FPREG;
105 			p = stref(block(STREF, r, p, 0, 0, 0));
106 			break;
107 
108 		case STATIC:
109 			if (q->slevel == 0)
110 				break;
111 			p->n_lval = 0;
112 			p->n_sp = q;
113 			break;
114 
115 		case REGISTER:
116 			p->n_op = REG;
117 			p->n_lval = 0;
118 			p->n_rval = q->soffset;
119 			break;
120 
121 			}
122 		break;
123 
124 	case STCALL:
125 	case CALL:
126 		/* Fix function call arguments. On x86, just add funarg */
127 		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
128 			if (r->n_right->n_op != STARG &&
129 			    r->n_right->n_op != FUNARG)
130 				r->n_right = block(FUNARG, r->n_right, NIL,
131 				    r->n_right->n_type, r->n_right->n_df,
132 				    r->n_right->n_sue);
133 		}
134 		if (r->n_op != STARG && r->n_op != FUNARG) {
135 			l = talloc();
136 			*l = *r;
137 			r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
138 		}
139 		break;
140 
141 	case CBRANCH:
142 		l = p->n_left;
143 
144 		/*
145 		 * Remove unnecessary conversion ops.
146 		 */
147 		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
148 			if (coptype(l->n_op) != BITYPE)
149 				break;
150 			if (l->n_right->n_op == ICON) {
151 				r = l->n_left->n_left;
152 				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
153 					break;
154 				/* Type must be correct */
155 				t = r->n_type;
156 				nfree(l->n_left);
157 				l->n_left = r;
158 				l->n_type = t;
159 				l->n_right->n_type = t;
160 			}
161 		}
162 		break;
163 
164 	case PCONV:
165 		/* Remove redundant PCONV's. Be careful */
166 		l = p->n_left;
167 		if (l->n_op == ICON) {
168 			l->n_lval = (unsigned)l->n_lval;
169 			goto delp;
170 		}
171 		if (l->n_type < INT || l->n_type == LONGLONG ||
172 		    l->n_type == ULONGLONG) {
173 			/* float etc? */
174 			p->n_left = block(SCONV, l, NIL,
175 			    UNSIGNED, 0, MKSUE(UNSIGNED));
176 			break;
177 		}
178 		/* if left is SCONV, cannot remove */
179 		if (l->n_op == SCONV)
180 			break;
181 		/* if conversion to another pointer type, just remove */
182 		if (p->n_type > BTMASK && l->n_type > BTMASK)
183 			goto delp;
184 		break;
185 
186 	delp:	l->n_type = p->n_type;
187 		l->n_qual = p->n_qual;
188 		l->n_df = p->n_df;
189 		l->n_sue = p->n_sue;
190 		nfree(p);
191 		p = l;
192 		break;
193 
194 	case SCONV:
195 		l = p->n_left;
196 
197 		if (p->n_type == l->n_type) {
198 			nfree(p);
199 			return l;
200 		}
201 
202 		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
203 		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
204 			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
205 			    l->n_type != FLOAT && l->n_type != DOUBLE &&
206 			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
207 				if (l->n_op == NAME || l->n_op == UMUL ||
208 				    l->n_op == TEMP) {
209 					l->n_type = p->n_type;
210 					nfree(p);
211 					return l;
212 				}
213 			}
214 		}
215 
216 		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
217 		    coptype(l->n_op) == BITYPE) {
218 			l->n_type = p->n_type;
219 			nfree(p);
220 			return l;
221 		}
222 
223 		o = l->n_op;
224 		m = p->n_type;
225 
226 		if (o == ICON) {
227 			CONSZ val = l->n_lval;
228 
229 			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
230 			    switch (m) {
231 			case CHAR:
232 				l->n_lval = (char)val;
233 				break;
234 			case UCHAR:
235 				l->n_lval = val & 0377;
236 				break;
237 			case SHORT:
238 				l->n_lval = (short)val;
239 				break;
240 			case USHORT:
241 				l->n_lval = val & 0177777;
242 				break;
243 			case ULONG:
244 			case UNSIGNED:
245 				l->n_lval = val & 0xffffffff;
246 				break;
247 			case LONG:
248 			case INT:
249 				l->n_lval = (int)val;
250 				break;
251 			case LONGLONG:
252 				l->n_lval = (long long)val;
253 				break;
254 			case ULONGLONG:
255 				l->n_lval = val;
256 				break;
257 			case VOID:
258 				break;
259 			case LDOUBLE:
260 			case DOUBLE:
261 			case FLOAT:
262 				l->n_op = FCON;
263 				l->n_dcon = val;
264 				break;
265 			default:
266 				cerror("unknown type %d", m);
267 			}
268 			l->n_type = m;
269 			l->n_sue = MKSUE(m);
270 			nfree(p);
271 			return l;
272 		}
273 		if (DEUNSIGN(p->n_type) == SHORT &&
274 		    DEUNSIGN(l->n_type) == SHORT) {
275 			nfree(p);
276 			p = l;
277 		}
278 		if ((p->n_type == CHAR || p->n_type == UCHAR ||
279 		    p->n_type == SHORT || p->n_type == USHORT) &&
280 		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
281 		    l->n_type == LDOUBLE)) {
282 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
283 			p->n_left->n_type = INT;
284 			return p;
285 		}
286 		break;
287 
288 	case MOD:
289 	case DIV:
290 		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
291 			break;
292 		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
293 			break;
294 		/* make it an int division by inserting conversions */
295 		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT));
296 		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT));
297 		p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type));
298 		p->n_left->n_type = INT;
299 		break;
300 
301 	case PMCONV:
302 	case PVCONV:
303                 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
304                 nfree(p);
305                 return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
306 
307 	case FORCE:
308 		/* put return value in return reg */
309 		p->n_op = ASSIGN;
310 		p->n_right = p->n_left;
311 		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
312 		p->n_left->n_rval = RETREG(p->n_type);
313 		break;
314 
315 	case LS:
316 	case RS:
317 		/* shift count must be in a char
318 		 * unless longlong, where it must be int */
319 		if (p->n_right->n_op == ICON)
320 			break; /* do not do anything */
321 		if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
322 			if (p->n_right->n_type != INT)
323 				p->n_right = block(SCONV, p->n_right, NIL,
324 				    INT, 0, MKSUE(INT));
325 			break;
326 		}
327 		if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
328 			break;
329 		p->n_right = block(SCONV, p->n_right, NIL,
330 		    CHAR, 0, MKSUE(CHAR));
331 		break;
332 	}
333 //printf("ut:\n");
334 //fwalk(p, eprint, 0);
335 
336 #endif
337 
338 	return(p);
339 }
340 
341 void
342 myp2tree(NODE *p)
343 {
344 	struct symtab *sp;
345 	int o = p->n_op, i;
346 
347 	if (o != FCON)
348 		return;
349 
350 	sp = inlalloc(sizeof(struct symtab));
351 	sp->sclass = STATIC;
352 	sp->ssue = MKSUE(p->n_type);
353 	sp->slevel = 1; /* fake numeric label */
354 	sp->soffset = getlab();
355 	sp->sflags = 0;
356 	sp->stype = p->n_type;
357 	sp->squal = (CON >> TSHIFT);
358 
359 	defloc(sp);
360 	ninval(0, sp->ssue->suesize, p);
361 
362 	p->n_op = NAME;
363 	p->n_lval = 0;
364 	p->n_sp = sp;
365 
366 }
367 
368 /*ARGSUSED*/
369 int
370 andable(NODE *p)
371 {
372 	return(1);  /* all names can have & taken on them */
373 }
374 
375 /*
376  * at the end of the arguments of a ftn, set the automatic offset
377  */
378 void
379 cendarg()
380 {
381 	autooff = AUTOINIT;
382 }
383 
384 /*
385  * Return 1 if a variable of type type is OK to put in register.
386  */
387 int
388 cisreg(TWORD t)
389 {
390 	return 1; /* try to put anything in a register */
391 }
392 
393 /*
394  * return a node, for structure references, which is suitable for
395  * being added to a pointer of type t, in order to be off bits offset
396  * into a structure
397  * t, d, and s are the type, dimension offset, and sizeoffset
398  * For nova, return the type-specific index number which calculation
399  * is based on its size. For example, char a[3] would return 3.
400  * Be careful about only handling first-level pointers, the following
401  * indirections must be fullword.
402  */
403 NODE *
404 offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
405 {
406 	register NODE *p;
407 
408 	if (xdebug)
409 		printf("offcon: OFFSZ %ld type %x dim %p siz %d\n",
410 		    off, t, d, sue->suesize);
411 
412 	p = bcon(0);
413 	p->n_lval = off/SZINT;	/* Default */
414 	if (ISPTR(DECREF(t)))
415 		return p;
416 	if (t == VOID || t == CHAR || t == UCHAR)
417 		p->n_lval = off/SZCHAR; /* pointer to char */
418 	return(p);
419 }
420 
421 /*
422  * Allocate off bits on the stack.  p is a tree that when evaluated
423  * is the multiply count for off, t is a NAME node where to write
424  * the allocated address.
425  */
426 void
427 spalloc(NODE *t, NODE *p, OFFSZ off)
428 {
429 	NODE *sp;
430 
431 cerror("spalloc");
432 	if ((off % SZINT) == 0)
433 		p =  buildtree(MUL, p, bcon(off/SZINT));
434 	else if ((off % SZSHORT) == 0) {
435 		p = buildtree(MUL, p, bcon(off/SZSHORT));
436 		p = buildtree(PLUS, p, bcon(1));
437 		p = buildtree(RS, p, bcon(1));
438 	} else if ((off % SZCHAR) == 0) {
439 		p = buildtree(MUL, p, bcon(off/SZCHAR));
440 		p = buildtree(PLUS, p, bcon(3));
441 		p = buildtree(RS, p, bcon(2));
442 	} else
443 		cerror("roundsp");
444 
445 	/* save the address of sp */
446 	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
447 	sp->n_lval = 0;
448 	sp->n_rval = STKREG;
449 	t->n_type = sp->n_type;
450 	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
451 
452 	/* add the size to sp */
453 	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
454 	sp->n_lval = 0;
455 	sp->n_rval = STKREG;
456 	ecomp(buildtree(PLUSEQ, sp, p));
457 }
458 
459 /*
460  * print out a constant node
461  * mat be associated with a label
462  */
463 void
464 ninval(NODE *p)
465 {
466 	struct symtab *q;
467 	TWORD t;
468 
469 	p = p->n_left;
470 	t = p->n_type;
471 	if (t > BTMASK)
472 		t = INT; /* pointer */
473 
474 	if (p->n_op != ICON)
475 		cerror("ninval: init node not constant");
476 
477 	switch (t) {
478 	case LONG:
479 	case ULONG:
480 		inval(p->n_lval & 0xffff);
481 		inval(p->n_lval >> 16);
482 		break;
483 	case INT:
484 	case UNSIGNED:
485 		printf("\t.word 0%o", (short)p->n_lval);
486 		if ((q = p->n_sp) != NULL) {
487 			if ((q->sclass == STATIC && q->slevel > 0)) {
488 				printf("+" LABFMT, q->soffset);
489 			} else
490 				printf("+%s", exname(q->soname));
491 		}
492 		printf("\n");
493 		break;
494 	default:
495 		cerror("ninval");
496 	}
497 }
498 
499 /*
500  * print out an integer.
501  */
502 void
503 inval(CONSZ word)
504 {
505 	word &= 0xffff;
506 	printf("	.word 0%o\n", (int)word);
507 }
508 
509 /* output code to initialize a floating point value */
510 /* the proper alignment has been obtained */
511 void
512 finval(NODE *p)
513 {
514 	union { float f; double d; long double l; int i[3]; } u;
515 
516 cerror("finval");
517 	switch (p->n_type) {
518 	case LDOUBLE:
519 		u.i[2] = 0;
520 		u.l = (long double)p->n_dcon;
521 		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
522 		break;
523 	case DOUBLE:
524 		u.d = (double)p->n_dcon;
525 		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
526 		break;
527 	case FLOAT:
528 		u.f = (float)p->n_dcon;
529 		printf("\t.long\t0x%x\n", u.i[0]);
530 		break;
531 	}
532 }
533 
534 /* make a name look like an external name in the local machine */
535 char *
536 exname(char *p)
537 {
538 	if (p == NULL)
539 		return "";
540 	return p;
541 }
542 
543 /*
544  * map types which are not defined on the local machine
545  */
546 TWORD
547 ctype(TWORD type)
548 {
549 	switch (BTYPE(type)) {
550 	case LONGLONG:
551 		MODTYPE(type,LONG);
552 		break;
553 
554 	case ULONGLONG:
555 		MODTYPE(type,ULONG);
556 		break;
557 	case SHORT:
558 		MODTYPE(type,INT);
559 		break;
560 	case USHORT:
561 		MODTYPE(type,UNSIGNED);
562 		break;
563 	}
564 	return (type);
565 }
566 
567 /* curid is a variable which is defined but
568  * is not initialized (and not a function );
569  * This routine returns the storage class for an uninitialized declaration
570  */
571 int
572 noinit()
573 {
574 	return(EXTERN);
575 }
576 
577 void
578 calldec(NODE *p, NODE *q)
579 {
580 }
581 
582 void
583 extdec(struct symtab *q)
584 {
585 }
586 
587 /* make a common declaration for id, if reasonable */
588 void
589 commdec(struct symtab *q)
590 {
591 	int off;
592 
593 	off = tsize(q->stype, q->sdf, q->ssue);
594 	off = (off+(SZCHAR-1))/SZCHAR;
595 	printf("	.comm %s,0%o\n", exname(q->soname), off);
596 }
597 
598 /* make a local common declaration for id, if reasonable */
599 void
600 lcommdec(struct symtab *q)
601 {
602 	int off;
603 
604 	off = tsize(q->stype, q->sdf, q->ssue);
605 	off = (off+(SZCHAR-1))/SZCHAR;
606 	if (q->slevel == 0)
607 		printf("	.lcomm %s,0%o\n", exname(q->soname), off);
608 	else
609 		printf("	.lcomm " LABFMT ",0%o\n", q->soffset, off);
610 }
611 
612 /*
613  * print a (non-prog) label.
614  */
615 void
616 deflab1(int label)
617 {
618 	printf(LABFMT ":\n", label);
619 }
620 
621 static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
622 
623 void
624 setloc1(int locc)
625 {
626 	if (locc == lastloc)
627 		return;
628 	lastloc = locc;
629 	printf("	.%s\n", loctbl[locc]);
630 }
631 /*
632  * Give target the opportunity of handling pragmas.
633  */
634 int
635 mypragma(char **ary)
636 {
637 	return 0; }
638 
639 /*
640  * Called when a identifier has been declared, to give target last word.
641  */
642 void
643 fixdef(struct symtab *sp)
644 {
645 }
646 
647 void
648 pass1_lastchance(struct interpass *ip)
649 {
650 }
651