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