xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/arm/local.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
1 /*      Id: local.c,v 1.33 2015/01/07 05:20:48 gmcgarry Exp     */
2 /*      $NetBSD: local.c,v 1.1.1.6 2016/02/09 20:28:11 plunky Exp $    */
3 /*
4  * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
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  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * We define location operations which operate on the expression tree
31  * during the first pass (before sending to the backend for code generation.)
32  */
33 
34 #include <assert.h>
35 
36 #include "pass1.h"
37 
38 extern void defalign(int);
39 
40 /*
41  * clocal() is called to do local transformations on
42  * an expression tree before being sent to the backend.
43  */
44 NODE *
clocal(NODE * p)45 clocal(NODE *p)
46 {
47 	struct symtab *q;
48 	NODE *l, *r, *t;
49 	int o;
50 	int ty;
51 	int tmpnr, isptrvoid = 0;
52 	char *n;
53 
54 	o = p->n_op;
55 	switch (o) {
56 
57 	case STASG:
58 
59 		l = p->n_left;
60 		r = p->n_right;
61 		if (r->n_op != STCALL && r->n_op != USTCALL)
62 			return p;
63 
64 		/* assign left node as first argument to function */
65 		nfree(p);
66 		t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap);
67 		l->n_rval = R0;
68 		l = buildtree(ADDROF, l, NIL);
69 		l = buildtree(ASSIGN, t, l);
70 
71 		if (r->n_right->n_op != CM) {
72 			r->n_right = block(CM, l, r->n_right, INT, 0, 0);
73 		} else {
74 			for (t = r->n_right; t->n_left->n_op == CM;
75 			    t = t->n_left)
76 				;
77 			t->n_left = block(CM, l, t->n_left, INT, 0, 0);
78 		}
79 		return r;
80 
81 	case CALL:
82 	case STCALL:
83 	case USTCALL:
84 		if (p->n_type == VOID)
85 			break;
86 		/*
87 		 * if the function returns void*, ecode() invokes
88 		 * delvoid() to convert it to uchar*.
89 		 * We just let this happen on the ASSIGN to the temp,
90 		 * and cast the pointer back to void* on access
91 		 * from the temp.
92 		 */
93 		if (p->n_type == PTR+VOID)
94 			isptrvoid = 1;
95 		r = tempnode(0, p->n_type, p->n_df, p->n_ap);
96 		tmpnr = regno(r);
97 		r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
98 
99 		p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
100 		if (isptrvoid) {
101 			p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0);
102 		}
103 		p = buildtree(COMOP, r, p);
104 		break;
105 
106 	case NAME:
107 		if ((q = p->n_sp) == NULL)
108 			return p;
109 		if (blevel == 0)
110 			return p;
111 
112 		switch (q->sclass) {
113 		case PARAM:
114 		case AUTO:
115 			/* fake up a structure reference */
116 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
117 			r->n_lval = 0;
118 			r->n_rval = FPREG;
119 			p = stref(block(STREF, r, p, 0, 0, 0));
120 			break;
121 		case REGISTER:
122 			p->n_op = REG;
123 			p->n_lval = 0;
124 			p->n_rval = q->soffset;
125 			break;
126 		case STATIC:
127 			if (q->slevel > 0) {
128 				p->n_lval = 0;
129 				p->n_sp = q;
130 			}
131 			/* FALL-THROUGH */
132 		default:
133 			ty = p->n_type;
134 			n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
135 			if (strncmp(n, "__builtin", 9) == 0)
136 				break;
137 			p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_ap);
138 			p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap);
139 			break;
140 		}
141 		break;
142 
143 	case STNAME:
144 		if ((q = p->n_sp) == NULL)
145 			return p;
146 		if (q->sclass != STNAME)
147 			return p;
148 		ty = p->n_type;
149 		p = block(ADDROF, p, NIL, INCREF(ty),
150 		    p->n_df, p->n_ap);
151 		p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap);
152 		break;
153 
154 	case FORCE:
155 		/* put return value in return reg */
156 		p->n_op = ASSIGN;
157 		p->n_right = p->n_left;
158 		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
159 		p->n_left->n_rval = p->n_left->n_type == BOOL ?
160 		    RETREG(BOOL_TYPE) : RETREG(p->n_type);
161 		break;
162 
163 	case SCONV:
164 		l = p->n_left;
165 		if (p->n_type == l->n_type) {
166 			nfree(p);
167 			return l;
168 		}
169 		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
170 		    tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) {
171 			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
172 			    l->n_type != FLOAT && l->n_type != DOUBLE &&
173 			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
174 				if (l->n_op == NAME || l->n_op == UMUL ||
175 				    l->n_op == TEMP) {
176 					l->n_type = p->n_type;
177 					nfree(p);
178 					return l;
179 				}
180 			}
181 		}
182 
183 		if (l->n_op == ICON) {
184 			CONSZ val = l->n_lval;
185 
186 			if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */
187 			switch (p->n_type) {
188 			case BOOL:
189 				l->n_lval = l->n_lval != 0;
190 				break;
191 			case CHAR:
192 				l->n_lval = (char)val;
193 				break;
194 			case UCHAR:
195 				l->n_lval = val & 0377;
196 				break;
197 			case SHORT:
198 				l->n_lval = (short)val;
199 				break;
200 			case USHORT:
201 				l->n_lval = val & 0177777;
202 				break;
203 			case ULONG:
204 			case UNSIGNED:
205 				l->n_lval = val & 0xffffffff;
206 				break;
207 			case LONG:
208 			case INT:
209 				l->n_lval = (int)val;
210 				break;
211 			case LONGLONG:
212 				l->n_lval = (long long)val;
213 				break;
214 			case ULONGLONG:
215 				l->n_lval = val;
216 				break;
217 			case VOID:
218 				break;
219 			case LDOUBLE:
220 			case DOUBLE:
221 			case FLOAT:
222 				l->n_op = FCON;
223 				l->n_dcon = val;
224 				break;
225 			default:
226 				cerror("unknown type %d", l->n_type);
227 			}
228 			l->n_type = p->n_type;
229 			l->n_ap = 0;
230 			nfree(p);
231 			return l;
232 		} else if (p->n_op == FCON) {
233 			l->n_lval = l->n_dcon;
234 			l->n_sp = NULL;
235 			l->n_op = ICON;
236 			l->n_type = p->n_type;
237 			l->n_ap = 0;
238 			nfree(p);
239 			return clocal(l);
240 		}
241 		if ((DEUNSIGN(p->n_type) == CHAR ||
242 		    DEUNSIGN(p->n_type) == SHORT) &&
243 		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
244 		    l->n_type == LDOUBLE)) {
245 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
246 			p->n_left->n_type = INT;
247 			return p;
248 		}
249 		break;
250 
251 	case PCONV:
252 		l = p->n_left;
253 		if (l->n_op == ICON) {
254 			l->n_lval = (unsigned)l->n_lval;
255 			goto delp;
256 		}
257 		if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
258 			p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
259 			break;
260 		}
261 		if (l->n_op == SCONV)
262 			break;
263 		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
264 			goto delp;
265 		if (p->n_type > BTMASK && l->n_type > BTMASK)
266 			goto delp;
267 		break;
268 
269 	delp:
270 		l->n_type = p->n_type;
271 		l->n_qual = p->n_qual;
272 		l->n_df = p->n_df;
273 		l->n_ap = p->n_ap;
274 		nfree(p);
275 		p = l;
276 		break;
277 	}
278 
279 	return p;
280 }
281 
282 /*
283  * Called before sending the tree to the backend.
284  */
285 void
myp2tree(NODE * p)286 myp2tree(NODE *p)
287 {
288 	struct symtab *sp;
289 
290 	if (p->n_op != FCON)
291 		return;
292 
293 #define IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
294 
295 	sp = IALLOC(sizeof(struct symtab));
296 	sp->sclass = STATIC;
297 	sp->sap = 0;
298 	sp->slevel = 1; /* fake numeric label */
299 	sp->soffset = getlab();
300 	sp->sflags = 0;
301 	sp->stype = p->n_type;
302 	sp->squal = (CON >> TSHIFT);
303 
304 	defloc(sp);
305 	ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
306 
307 	p->n_op = NAME;
308 	p->n_lval = 0;
309 	p->n_sp = sp;
310 }
311 
312 /*
313  * Called during the first pass to determine if a NAME can be addressed.
314  *
315  * Return nonzero if supported, otherwise return 0.
316  */
317 int
andable(NODE * p)318 andable(NODE *p)
319 {
320 	if (blevel == 0)
321 		return 1;
322 	if (ISFTN(p->n_type))
323 		return 1;
324 	return 0;
325 }
326 
327 /*
328  * Return 1 if a variable of type 't' is OK to put in register.
329  */
330 int
cisreg(TWORD t)331 cisreg(TWORD t)
332 {
333 	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
334 		return 0; /* not yet */
335 	return 1;
336 }
337 
338 /*
339  * Allocate bits from the stack for dynamic-sized arrays.
340  *
341  * 'p' is the tree which represents the type being allocated.
342  * 'off' is the number of 'p's to be allocated.
343  * 't' is the storeable node where the address is written.
344  */
345 void
spalloc(NODE * t,NODE * p,OFFSZ off)346 spalloc(NODE *t, NODE *p, OFFSZ off)
347 {
348 	NODE *sp;
349 
350 	p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
351 
352 	/* sub the size from sp */
353 	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
354 	sp->n_lval = 0;
355 	sp->n_rval = SP;
356 	ecomp(buildtree(MINUSEQ, sp, p));
357 
358 	/* save the address of sp */
359 	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
360 	sp->n_lval = 0;
361 	sp->n_rval = SP;
362 	t->n_type = sp->n_type;
363 	ecomp(buildtree(ASSIGN, t, sp));
364 }
365 
366 /*
367  * Print an integer constant node, may be associated with a label.
368  * Do not free the node after use.
369  * 'off' is bit offset from the beginning of the aggregate
370  * 'fsz' is the number of bits this is referring to
371  */
372 int
ninval(CONSZ off,int fsz,NODE * p)373 ninval(CONSZ off, int fsz, NODE *p)
374 {
375 	union { float f; double d; int i[2]; } u;
376 	struct symtab *q;
377 	TWORD t;
378 	int i, j;
379 
380 	t = p->n_type;
381 	if (t > BTMASK)
382 		t = p->n_type = INT; /* pointer */
383 
384 	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
385 		uerror("element not constant");
386 
387 	switch (t) {
388 	case LONGLONG:
389 	case ULONGLONG:
390 		i = (p->n_lval >> 32);
391 		j = (p->n_lval & 0xffffffff);
392 		p->n_type = INT;
393 		if (features(FEATURE_BIGENDIAN)) {
394 			p->n_lval = i;
395 			ninval(off+32, 32, p);
396 			p->n_lval = j;
397 			ninval(off, 32, p);
398 		} else {
399 			p->n_lval = j;
400 			ninval(off, 32, p);
401 			p->n_lval = i;
402 			ninval(off+32, 32, p);
403 		}
404 		break;
405 	case INT:
406 	case UNSIGNED:
407 		printf("\t.word 0x%x", (int)p->n_lval);
408 		if ((q = p->n_sp) != NULL) {
409 			if ((q->sclass == STATIC && q->slevel > 0)) {
410 				printf("+" LABFMT, q->soffset);
411 			} else
412 				printf("+%s",
413 				    q->soname ? q->soname : exname(q->sname));
414 		}
415 		printf("\n");
416 		break;
417 	case LDOUBLE:
418 	case DOUBLE:
419 		u.d = (double)p->n_dcon;
420 #if defined(HOST_BIG_ENDIAN)
421 		if (features(FEATURE_BIGENDIAN))
422 #else
423 		if (!features(FEATURE_BIGENDIAN))
424 #endif
425 			printf("\t.word\t0x%x\n\t.word\t0x%x\n",
426 			    u.i[0], u.i[1]);
427 		else
428 			printf("\t.word\t0x%x\n\t.word\t0x%x\n",
429 			    u.i[1], u.i[0]);
430 		break;
431 	case FLOAT:
432 		u.f = (float)p->n_dcon;
433 		printf("\t.word\t0x%x\n", u.i[0]);
434 		break;
435 	default:
436 		return 0;
437 	}
438 	return 1;
439 }
440 
441 /*
442  * Prefix a leading underscore to a global variable (if necessary).
443  */
444 char *
exname(char * p)445 exname(char *p)
446 {
447 	return (p == NULL ? "" : p);
448 }
449 
450 /*
451  * Map types which are not defined on the local machine.
452  */
453 TWORD
ctype(TWORD type)454 ctype(TWORD type)
455 {
456 	switch (BTYPE(type)) {
457 	case LONG:
458 		MODTYPE(type,INT);
459 		break;
460 	case ULONG:
461 		MODTYPE(type,UNSIGNED);
462 		break;
463 	}
464 	return (type);
465 }
466 
467 /*
468  * Before calling a function do any tree re-writing for the local machine.
469  *
470  * 'p' is the function tree (NAME)
471  * 'q' is the CM-separated list of arguments.
472  */
473 void
calldec(NODE * p,NODE * q)474 calldec(NODE *p, NODE *q)
475 {
476 }
477 
478 /*
479  * While handling uninitialised variables, handle variables marked extern.
480  */
481 void
extdec(struct symtab * q)482 extdec(struct symtab *q)
483 {
484 }
485 
486 /* make a common declaration for id, if reasonable */
487 void
defzero(struct symtab * sp)488 defzero(struct symtab *sp)
489 {
490 	int off;
491 
492 	off = tsize(sp->stype, sp->sdf, sp->sap);
493 	off = (off+(SZCHAR-1))/SZCHAR;
494 	printf("	.%scomm ", sp->sclass == STATIC ? "l" : "");
495 	if (sp->slevel == 0)
496 		printf("%s,0%o\n",
497 		    sp->soname ? sp->soname : exname(sp->sname), off);
498 	else
499 		printf(LABFMT ",0%o\n", sp->soffset, off);
500 }
501 
502 /*
503  * va_start(ap, last) implementation.
504  *
505  * f is the NAME node for this builtin function.
506  * a is the argument list containing:
507  *	   CM
508  *	ap   last
509  */
510 NODE *
arm_builtin_stdarg_start(const struct bitable * bt,NODE * a)511 arm_builtin_stdarg_start(const struct bitable *bt, NODE *a)
512 {
513 	NODE *p, *q;
514 	int sz = 1;
515 
516 	/* check num args and type */
517 	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
518 	    !ISPTR(a->n_left->n_type))
519 		goto bad;
520 
521 	/* must first deal with argument size; use int size */
522 	p = a->n_right;
523 	if (p->n_type < INT) {
524 		/* round up to word */
525 		sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
526 	}
527 
528 	p = buildtree(ADDROF, p, NIL);  /* address of last arg */
529 	p = optim(buildtree(PLUS, p, bcon(sz)));
530 	q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
531 	q = buildtree(CAST, q, p);
532 	p = q->n_right;
533 	nfree(q->n_left);
534 	nfree(q);
535 	p = buildtree(ASSIGN, a->n_left, p);
536 	nfree(a);
537 
538 	return p;
539 
540 bad:
541 	uerror("bad argument to __builtin_stdarg_start");
542 	return bcon(0);
543 }
544 
545 NODE *
arm_builtin_va_arg(const struct bitable * bt,NODE * a)546 arm_builtin_va_arg(const struct bitable *bt, NODE *a)
547 {
548 	NODE *p, *q, *r;
549 	int sz, tmpnr;
550 
551 	/* check num args and type */
552 	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
553 	    !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
554 		goto bad;
555 
556 	r = a->n_right;
557 
558 	/* get type size */
559 	sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
560 	if (sz < SZINT/SZCHAR) {
561 		werror("%s%s promoted to int when passed through ...",
562 			ISUNSIGNED(r->n_type) ? "unsigned " : "",
563 			DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
564 		sz = SZINT/SZCHAR;
565 	}
566 
567 	/* alignment */
568 	p = tcopy(a->n_left);
569 	if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
570 		p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
571 		p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap);
572 	}
573 
574 	/* create a copy to a temp node */
575 	q = tempnode(0, p->n_type, p->n_df, p->n_ap);
576 	tmpnr = regno(q);
577 	p = buildtree(ASSIGN, q, p);
578 
579 	q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
580 	q = buildtree(PLUS, q, bcon(sz));
581 	q = buildtree(ASSIGN, a->n_left, q);
582 
583 	q = buildtree(COMOP, p, q);
584 
585 	nfree(a->n_right);
586 	nfree(a);
587 
588 	p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
589 	p = buildtree(UMUL, p, NIL);
590 	p = buildtree(COMOP, q, p);
591 
592 	return p;
593 
594 bad:
595 	uerror("bad argument to __builtin_va_arg");
596 	return bcon(0);
597 }
598 
599 NODE *
arm_builtin_va_end(const struct bitable * bt,NODE * a)600 arm_builtin_va_end(const struct bitable *bt, NODE *a)
601 {
602 	tfree(a);
603 
604 	return bcon(0);
605 }
606 
607 NODE *
arm_builtin_va_copy(const struct bitable * bt,NODE * a)608 arm_builtin_va_copy(const struct bitable *bt, NODE *a)
609 {
610 	NODE  *f;
611 
612 	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
613 		goto bad;
614 	f = buildtree(ASSIGN, a->n_left, a->n_right);
615 	nfree(a);
616 	return f;
617 
618 bad:
619 	uerror("bad argument to __buildtin_va_copy");
620 	return bcon(0);
621 }
622 
623 char *nextsect;
624 static int constructor;
625 static int destructor;
626 
627 /*
628  * Give target the opportunity of handling pragmas.
629  */
630 int
mypragma(char * str)631 mypragma(char *str)
632 {
633 	char *a2 = pragtok(NULL);
634 
635 	if (strcmp(str, "tls") == 0) {
636 		uerror("thread-local storage not supported for this target");
637 		return 1;
638 	}
639 	if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
640 		constructor = 1;
641 		return 1;
642 	}
643 	if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
644 		destructor = 1;
645 		return 1;
646 	}
647 	if (strcmp(str, "section") == 0 && a2 != NULL) {
648 		nextsect = newstring(a2, strlen(a2));
649 		return 1;
650 	}
651 
652 	return 0;
653 }
654 
655 /*
656  * Called when a identifier has been declared, to give target last word.
657  */
658 void
fixdef(struct symtab * sp)659 fixdef(struct symtab *sp)
660 {
661 	if ((constructor || destructor) && (sp->sclass != PARAM)) {
662 		printf("\t.section .%ctors,\"aw\",@progbits\n",
663 		    constructor ? 'c' : 'd');
664 		printf("\t.p2align 2\n");
665 		printf("\t.long %s\n", exname(sp->sname));
666 		printf("\t.previous\n");
667 		constructor = destructor = 0;
668 	}
669 }
670 
671 void
pass1_lastchance(struct interpass * ip)672 pass1_lastchance(struct interpass *ip)
673 {
674 }
675