xref: /netbsd/external/bsd/pcc/dist/pcc/arch/powerpc/local.c (revision 370d6aa0)
1 /*	Id: local.c,v 1.34 2012/09/06 13:07:29 plunky Exp 	*/
2 /*	$NetBSD: local.c,v 1.1.1.5 2014/07/24 19:20:27 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include "pass1.h"
30 
31 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
32 
33 extern int kflag;
34 
35 static void simmod(NODE *p);
36 
37 /*	this file contains code which is dependent on the target machine */
38 
39 #if defined(MACHOABI)
40 
41 /*
42  *  Keep track of PIC stubs.
43  */
44 
45 void
addstub(struct stub * list,char * name)46 addstub(struct stub *list, char *name)
47 {
48         struct stub *s;
49 
50         DLIST_FOREACH(s, list, link) {
51                 if (strcmp(s->name, name) == 0)
52                         return;
53         }
54 
55         s = permalloc(sizeof(struct stub));
56 	s->name = newstring(name, strlen(name));
57         DLIST_INSERT_BEFORE(list, s, link);
58 }
59 
60 #endif
61 
62 
63 /*
64  * Make a symtab entry for PIC use.
65  */
66 static struct symtab *
picsymtab(char * p,char * s,char * s2)67 picsymtab(char *p, char *s, char *s2)
68 {
69 	struct symtab *sp = IALLOC(sizeof(struct symtab));
70 	size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
71 
72 	sp->sname = sp->soname = IALLOC(len);
73 	strlcpy(sp->soname, p, len);
74 	strlcat(sp->soname, s, len);
75 	strlcat(sp->soname, s2, len);
76 	sp->sclass = EXTERN;
77 	sp->sflags = sp->slevel = 0;
78 
79 	return sp;
80 }
81 
82 int gotnr;  /* tempnum for GOT register */
83 
84 /*
85  * Create a reference for an extern variable.
86  */
87 static NODE *
picext(NODE * p)88 picext(NODE *p)
89 {
90 	NODE *q;
91 	struct symtab *sp;
92 	char *name;
93 
94 	name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
95 
96 	if (strncmp(name, "__builtin", 9) == 0)
97 		return p;
98 
99 #if defined(ELFABI)
100 
101 	sp = picsymtab("", name, "@got(31)");
102 	q = xbcon(0, sp, PTR+VOID);
103 	q = block(UMUL, q, 0, PTR+VOID, 0, 0);
104 
105 #elif defined(MACHOABI)
106 
107 	char buf2[64];
108 	NODE *r;
109 	char *fname;
110 
111 	fname = cftnsp->soname ? cftnsp->soname : cftnsp->sname;
112 
113 	if (p->n_sp->sclass == EXTDEF) {
114 		snprintf(buf2, 64, "-L%s$pb", fname);
115 		sp = picsymtab("", name, buf2);
116 	} else {
117 		snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", fname);
118 		sp = picsymtab("L", name, buf2);
119 		addstub(&nlplist, name);
120 	}
121 #if USE_GOTNR
122 	q = tempnode(gotnr, PTR+VOID, 0, 0);
123 #else
124 	q = block(REG, NIL, NIL, PTR+VOID, 0, 0);
125 	regno(q) = GOTREG;
126 #endif
127 	r = xbcon(0, sp, INT);
128 	q = buildtree(PLUS, q, r);
129 
130 	if (p->n_sp->sclass != EXTDEF)
131 		q = block(UMUL, q, 0, PTR+VOID, 0, 0);
132 
133 #endif
134 
135 	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
136 	q->n_sp = p->n_sp; /* for init */
137 	nfree(p);
138 
139 	return q;
140 }
141 
142 /*
143  * Create a reference for a static variable
144  */
145 
146 static NODE *
picstatic(NODE * p)147 picstatic(NODE *p)
148 {
149 	NODE *q;
150 	struct symtab *sp;
151 
152 #if defined(ELFABI)
153 	char *n;
154 
155 	if (p->n_sp->slevel > 0) {
156 		char buf[64];
157 		snprintf(buf, 64, LABFMT, (int)p->n_sp->soffset);
158 		sp = picsymtab("", buf, "@got(31)");
159 	} else  {
160 		n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
161 		sp = picsymtab("", exname(n), "@got(31)");
162 	}
163 	sp->sclass = STATIC;
164 	sp->stype = p->n_sp->stype;
165 	q = xbcon(0, sp, PTR+VOID);
166 	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
167 	q->n_sp = p->n_sp;
168 	nfree(p);
169 
170 #elif defined(MACHOABI)
171 
172 	char buf2[64];
173 	NODE *r;
174 
175 	snprintf(buf2, 64, "-L%s$pb",
176 	    cftnsp->soname ? cftnsp->soname : cftnsp->sname);
177 
178 	if (p->n_sp->slevel > 0) {
179 		char buf1[64];
180 		snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset);
181 		sp = picsymtab("", buf1, buf2);
182 	} else  {
183 		char *name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
184 		sp = picsymtab("", name, buf2);
185 	}
186 	sp->sclass = STATIC;
187 	sp->stype = p->n_sp->stype;
188 #if USE_GOTNR
189 	q = tempnode(gotnr, PTR+VOID, 0, 0);
190 #else
191 	q = block(REG, NIL, NIL, PTR+VOID, 0, 0);
192 	regno(q) = GOTREG;
193 #endif
194 	r = xbcon(0, sp, INT);
195 	q = buildtree(PLUS, q, r);
196 	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
197 	q->n_sp = p->n_sp;
198 	nfree(p);
199 
200 #endif
201 
202 	return q;
203 }
204 
205 static NODE *
convert_ulltof(NODE * p)206 convert_ulltof(NODE *p)
207 {
208 	NODE *q, *r, *l, *t;
209 	int ty;
210 	int tmpnr;
211 
212 	ty = p->n_type;
213 	l = p->n_left;
214 	nfree(p);
215 
216 	q = tempnode(0, ULONGLONG, 0, 0);
217 	tmpnr = regno(q);
218 	t = buildtree(ASSIGN, q, l);
219 	ecomp(t);
220 
221 #if 0
222 	q = tempnode(tmpnr, ULONGLONG, 0, 0);
223 	q = block(SCONV, q, NIL, LONGLONG, 0, 0);
224 #endif
225 	q = tempnode(tmpnr, LONGLONG, 0, 0);
226 	r = block(SCONV, q, NIL, ty, 0, 0);
227 
228 	q = tempnode(tmpnr, ULONGLONG, 0, 0);
229 	q = block(RS, q, bcon(1), ULONGLONG, 0, 0);
230 	q = block(SCONV, q, NIL, LONGLONG, 0, 0);
231 	q = block(SCONV, q, NIL, ty, 0, 0);
232 	t = block(FCON, NIL, NIL, ty, 0, 0);
233 	t->n_dcon = 2;
234 	l = block(MUL, q, t, ty, 0, 0);
235 
236 	r = buildtree(COLON, l, r);
237 
238 	q = tempnode(tmpnr, ULONGLONG, 0, 0);
239 	q = block(SCONV, q, NIL, LONGLONG, 0, 0);
240 	l = block(LE, q, xbcon(0, NULL, LONGLONG), INT, 0, 0);
241 
242 	return clocal(buildtree(QUEST, l, r));
243 
244 }
245 
246 
247 /* clocal() is called to do local transformations on
248  * an expression tree preparitory to its being
249  * written out in intermediate code.
250  *
251  * the major essential job is rewriting the
252  * automatic variables and arguments in terms of
253  * REG and OREG nodes
254  * conversion ops which are not necessary are also clobbered here
255  * in addition, any special features (such as rewriting
256  * exclusive or) are easily handled here as well
257  */
258 NODE *
clocal(NODE * p)259 clocal(NODE *p)
260 {
261 
262 	struct symtab *q;
263 	NODE *r, *l;
264 	int o;
265 	int m;
266 	TWORD t;
267 	int isptrvoid = 0;
268 	int tmpnr;
269 
270 #ifdef PCC_DEBUG
271 	if (xdebug) {
272 		printf("clocal: %p\n", p);
273 		fwalk(p, eprint, 0);
274 	}
275 #endif
276 	switch (o = p->n_op) {
277 
278 	case ADDROF:
279 #ifdef PCC_DEBUG
280 		if (xdebug) {
281 			printf("clocal(): ADDROF\n");
282 			printf("type: 0x%x\n", p->n_type);
283 		}
284 #endif
285 		/* XXX cannot takes addresses of PARAMs */
286 
287 		if (kflag == 0 || blevel == 0)
288 			break;
289 		/* char arrays may end up here */
290 		l = p->n_left;
291 		if (l->n_op != NAME ||
292 		    (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
293 			break;
294 		l = p;
295 		p = picstatic(p->n_left);
296 		nfree(l);
297 		if (p->n_op != UMUL)
298 			cerror("ADDROF error");
299 		l = p;
300 		p = p->n_left;
301 		nfree(l);
302 		break;
303 
304 	case NAME:
305 		if ((q = p->n_sp) == NULL)
306 			return p; /* Nothing to care about */
307 
308 		switch (q->sclass) {
309 
310 		case PARAM:
311 		case AUTO:
312 			/* fake up a structure reference */
313 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
314 			r->n_lval = 0;
315 			r->n_rval = FPREG;
316 			p = stref(block(STREF, r, p, 0, 0, 0));
317 			break;
318 
319 		case USTATIC:
320 			if (kflag == 0)
321 				break;
322 			/* FALLTHROUGH */
323 
324 		case STATIC:
325 			if (kflag == 0) {
326 				if (q->slevel == 0)
327 					break;
328 				p->n_lval = 0;
329 			} else if (blevel > 0) {
330 				p = picstatic(p);
331 			}
332 			break;
333 
334 		case REGISTER:
335 			p->n_op = REG;
336 			p->n_lval = 0;
337 			p->n_rval = q->soffset;
338 			break;
339 
340 		case EXTERN:
341 		case EXTDEF:
342 			if (kflag == 0)
343 				break;
344 			if (blevel > 0)
345 				p = picext(p);
346 			break;
347 		}
348 		break;
349 
350 	case UCALL:
351 	case CALL:
352 	case USTCALL:
353 	case STCALL:
354                 if (p->n_type == VOID)
355                         break;
356                 /*
357                  * if the function returns void*, ecode() invokes
358                  * delvoid() to convert it to uchar*.
359                  * We just let this happen on the ASSIGN to the temp,
360                  * and cast the pointer back to void* on access
361                  * from the temp.
362                  */
363                 if (p->n_type == PTR+VOID)
364                         isptrvoid = 1;
365                 r = tempnode(0, p->n_type, p->n_df, p->n_ap);
366                 tmpnr = regno(r);
367 		r = buildtree(ASSIGN, r, p);
368 
369                 p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
370                 if (isptrvoid) {
371                         p = block(PCONV, p, NIL, PTR+VOID,
372                             p->n_df, 0);
373                 }
374 #if 1
375                 p = buildtree(COMOP, r, p);
376 #else
377 		/* XXX this doesn't work if the call is already in a COMOP */
378 		r = clocal(r);
379 		ecomp(r);
380 #endif
381                 break;
382 
383 	case CBRANCH:
384 		l = p->n_left;
385 
386 		/*
387 		 * Remove unnecessary conversion ops.
388 		 */
389 		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
390 			if (coptype(l->n_op) != BITYPE)
391 				break;
392 			if (l->n_right->n_op == ICON) {
393 				r = l->n_left->n_left;
394 				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
395 					break;
396 				/* Type must be correct */
397 				t = r->n_type;
398 				nfree(l->n_left);
399 				l->n_left = r;
400 				l->n_type = t;
401 				l->n_right->n_type = t;
402 			}
403 		}
404 		break;
405 
406 	case PCONV:
407 		/* Remove redundant PCONV's. Be careful */
408 		l = p->n_left;
409 		if (l->n_op == ICON) {
410 			l->n_lval = (unsigned)l->n_lval;
411 			goto delp;
412 		}
413 		if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
414 			/* float etc? */
415 			p->n_left = block(SCONV, l, NIL,
416 			    UNSIGNED, 0, 0);
417 			break;
418 		}
419 		/* if left is SCONV, cannot remove */
420 		if (l->n_op == SCONV)
421 			break;
422 
423 		/* avoid ADDROF TEMP */
424 		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
425 			break;
426 
427 		/* if conversion to another pointer type, just remove */
428 		if (p->n_type > BTMASK && l->n_type > BTMASK)
429 			goto delp;
430 		break;
431 
432 	delp:	l->n_type = p->n_type;
433 		l->n_qual = p->n_qual;
434 		l->n_df = p->n_df;
435 		l->n_ap = p->n_ap;
436 		nfree(p);
437 		p = l;
438 		break;
439 
440 	case SCONV:
441 		l = p->n_left;
442 
443 		if (p->n_type == l->n_type) {
444 			nfree(p);
445 			return l;
446 		}
447 
448 		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
449 		    tsize(p->n_type, p->n_df, p->n_ap) ==
450 		    tsize(l->n_type, l->n_df, l->n_ap)) {
451 			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
452 			    l->n_type != FLOAT && l->n_type != DOUBLE &&
453 			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
454 				if (l->n_op == NAME || l->n_op == UMUL ||
455 				    l->n_op == TEMP) {
456 					l->n_type = p->n_type;
457 					nfree(p);
458 					return l;
459 				}
460 			}
461 		}
462 
463 		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
464 		    coptype(l->n_op) == BITYPE) {
465 			l->n_type = p->n_type;
466 			nfree(p);
467 			return l;
468 		}
469 
470 		/*
471 		 * if converting ULONGLONG to FLOAT/(L)DOUBLE,
472 		 * replace ___floatunsdidf() with ___floatdidf()
473 		 */
474 		if (l->n_type == ULONGLONG && p->n_type >= FLOAT &&
475 		    p->n_type <= LDOUBLE) {
476 			return convert_ulltof(p);
477 		}
478 
479 		o = l->n_op;
480 		m = p->n_type;
481 
482 		if (o == ICON) {
483 			CONSZ val = l->n_lval;
484 
485 			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
486 			    switch (m) {
487 			case BOOL:
488 				l->n_lval = l->n_lval != 0;
489 				break;
490 			case CHAR:
491 				l->n_lval = (char)val;
492 				break;
493 			case UCHAR:
494 				l->n_lval = val & 0377;
495 				break;
496 			case SHORT:
497 				l->n_lval = (short)val;
498 				break;
499 			case USHORT:
500 				l->n_lval = val & 0177777;
501 				break;
502 			case ULONG:
503 			case UNSIGNED:
504 				l->n_lval = val & 0xffffffff;
505 				break;
506 			case LONG:
507 			case INT:
508 				l->n_lval = (int)val;
509 				break;
510 			case LONGLONG:
511 				l->n_lval = (long long)val;
512 				break;
513 			case ULONGLONG:
514 				l->n_lval = val;
515 				break;
516 			case VOID:
517 				break;
518 			case LDOUBLE:
519 			case DOUBLE:
520 			case FLOAT:
521 				l->n_op = FCON;
522 				l->n_dcon = val;
523 				break;
524 			default:
525 				cerror("unknown type %d", m);
526 			}
527 			l->n_type = m;
528 			l->n_ap = 0;
529 			nfree(p);
530 			return l;
531 		} else if (o == FCON) {
532 			l->n_lval = l->n_dcon;
533 			l->n_sp = NULL;
534 			l->n_op = ICON;
535 			l->n_type = m;
536 			l->n_ap = 0;
537 			nfree(p);
538 			return clocal(l);
539 		}
540 		if (DEUNSIGN(p->n_type) == SHORT &&
541 		    DEUNSIGN(l->n_type) == SHORT) {
542 			nfree(p);
543 			p = l;
544 		}
545 		if ((DEUNSIGN(p->n_type) == CHAR ||
546 		    DEUNSIGN(p->n_type) == SHORT) &&
547 		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
548 		    l->n_type == LDOUBLE)) {
549 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
550 			p->n_left->n_type = INT;
551 			return p;
552 		}
553 		if ((DEUNSIGN(l->n_type) == CHAR ||
554 		    DEUNSIGN(l->n_type) == SHORT) &&
555 		    (p->n_type == FLOAT || p->n_type == DOUBLE ||
556 		    p->n_type == LDOUBLE)) {
557 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
558 			p->n_left->n_type = INT;
559 			return p;
560 		}
561 		break;
562 
563 	case MOD:
564 		simmod(p);
565 		break;
566 
567 	case DIV:
568 		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
569 			break;
570 		/* make it an int division by inserting conversions */
571 		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
572 		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
573 		p = block(SCONV, p, NIL, p->n_type, 0, 0);
574 		p->n_left->n_type = INT;
575 		break;
576 
577 	case STNAME:
578 		if ((q = p->n_sp) == NULL)
579 			return p;
580 		if (q->sclass != STNAME)
581 			return p;
582 		t = p->n_type;
583 		p = block(ADDROF, p, NIL, INCREF(t), p->n_df, p->n_ap);
584 		p = block(UMUL, p, NIL, t, p->n_df, p->n_ap);
585 		break;
586 
587 	case FORCE:
588 		/* put return value in return reg */
589 		p->n_op = ASSIGN;
590 		p->n_right = p->n_left;
591 		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
592 		p->n_left->n_rval = p->n_left->n_type == BOOL ?
593 		    RETREG(BOOL_TYPE) : RETREG(p->n_type);
594 		break;
595 
596 	case LS:
597 	case RS:
598 		if (p->n_right->n_op == ICON)
599 			break; /* do not do anything */
600 		if (DEUNSIGN(p->n_right->n_type) == INT)
601 			break;
602 		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
603 		break;
604 	}
605 
606 #ifdef PCC_DEBUG
607 	if (xdebug) {
608 		printf("clocal end: %p\n", p);
609 		fwalk(p, eprint, 0);
610 	}
611 #endif
612 	return(p);
613 }
614 
615 /*
616  * Change CALL references to either direct (static) or PLT.
617  */
618 static void
fixnames(NODE * p,void * arg)619 fixnames(NODE *p, void *arg)
620 {
621         struct symtab *sp;
622         struct attr *ap;
623         NODE *q;
624         char *c;
625         int isu;
626 
627         if ((cdope(p->n_op) & CALLFLG) == 0)
628                 return;
629 
630         isu = 0;
631         q = p->n_left;
632         ap = q->n_ap;
633         if (q->n_op == UMUL)
634                 q = q->n_left, isu = 1;
635 
636 #if defined(ELFABI)
637 
638         if (q->n_op == ICON) {
639                 sp = q->n_sp;
640 
641 #elif defined(MACHOABI)
642 
643 #ifdef USE_GOTNR
644 	if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
645 #else
646 	if (q->n_op == PLUS && q->n_left->n_op == REG &&
647 #endif
648 	    q->n_right->n_op == ICON) {
649                 sp = q->n_right->n_sp;
650 #endif
651 
652                 if (sp == NULL)
653                         return; /* nothing to do */
654                 if (sp->sclass == STATIC && !ISFTN(sp->stype))
655                         return; /* function pointer */
656 
657                 if (sp->sclass != STATIC && sp->sclass != EXTERN &&
658                     sp->sclass != EXTDEF)
659                         cerror("fixnames");
660 		c = NULL;
661 #if defined(ELFABI)
662 
663 		if (sp->soname == NULL ||
664                     (c = strstr(sp->soname, "@got(31)")) == NULL)
665                         cerror("fixnames2");
666                 if (isu) {
667 			memcpy(c, "@plt", sizeof("@plt"));
668                 } else
669                         *c = 0;
670 
671 #elif defined(MACHOABI)
672 
673 		if (sp->soname == NULL ||
674 		    ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL &&
675 		    (c = strstr(sp->soname, "-L")) == NULL))
676 				cerror("fixnames2");
677 		if (isu) {
678 			addstub(&stublist, sp->soname+1);
679 			memcpy(c, "$stub", sizeof("$stub"));
680 		} else
681 			*c = 0;
682 
683 		nfree(q->n_left);
684 		q = q->n_right;
685 		if (isu)
686 			nfree(p->n_left->n_left);
687 		nfree(p->n_left);
688 		p->n_left = q;
689 		q->n_ap = ap;
690 
691 #endif
692         }
693 }
694 
695 void
696 myp2tree(NODE *p)
697 {
698 	int o = p->n_op;
699 	struct symtab *sp;
700 
701 	if (kflag)
702 		walkf(p, fixnames, 0);
703 	if (o != FCON)
704 		return;
705 
706 	/* Write float constants to memory */
707 	/* Should be voluntary per architecture */
708 
709 	sp = IALLOC(sizeof(struct symtab));
710 	sp->sclass = STATIC;
711 	sp->sap = 0;
712 	sp->slevel = 1; /* fake numeric label */
713 	sp->soffset = getlab();
714 	sp->sflags = 0;
715 	sp->stype = p->n_type;
716 	sp->squal = (CON >> TSHIFT);
717 
718 	defloc(sp);
719 	ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
720 
721 	p->n_op = NAME;
722 	p->n_lval = 0;
723 	p->n_sp = sp;
724 }
725 
726 /*ARGSUSED*/
727 int
728 andable(NODE *p)
729 {
730 	return(1);  /* all names can have & taken on them */
731 }
732 
733 /*
734  * Return 1 if a variable of type type is OK to put in register.
735  */
736 int
737 cisreg(TWORD t)
738 {
739 	return 1;
740 }
741 
742 /*
743  * Allocate bits on the stack.
744  * 'off' is the number of bits to allocate
745  * 'p' is a tree that when evaluated is the multiply count for 'off'
746  * 't' is a storeable node where to write the allocated address
747  */
748 void
749 spalloc(NODE *t, NODE *p, OFFSZ off)
750 {
751 	NODE *q, *r;
752 	int nbytes = off / SZCHAR;
753 	int stacksize = 24+40; /* this should be p2stacksize */
754 
755 	/*
756 	 * After we subtract the requisite bytes
757 	 * off the stack, we need to step back over
758 	 * the 40 bytes for the arguments registers
759 	 * *and* any other parameters which will get
760 	 * saved to the stack.  Unfortunately, we
761 	 * don't have that information in pass1 and
762 	 * the parameters will stomp on the allocated
763 	 * space for alloca().
764 	 *
765 	 * No fix yet.
766 	 */
767 	werror("parameters may stomp on alloca()");
768 
769 	/* compute size */
770 	p = buildtree(MUL, p, bcon(nbytes));
771 	p = buildtree(PLUS, p, bcon(ALSTACK/SZCHAR));
772 
773 	/* load the top-of-stack */
774 	q = block(REG, NIL, NIL, PTR+INT, 0, 0);
775 	regno(q) = SPREG;
776 	q = block(UMUL, q, NIL, INT, 0, 0);
777 
778 	/* save old top-of-stack value to new top-of-stack position */
779 	r = block(REG, NIL, NIL, PTR+INT, 0, 0);
780 	regno(r) = SPREG;
781 	r = block(MINUSEQ, r, p, INT, 0, 0);
782 	r = block(UMUL, r, NIL, INT, 0, 0);
783 	ecomp(buildtree(ASSIGN, r, q));
784 
785 	r = block(REG, NIL, NIL, PTR+INT, 0, 0);
786 	regno(r) = SPREG;
787 
788 	/* skip over the arguments space and align to 16 bytes */
789 	r = block(PLUS, r, bcon(stacksize + 15), INT, 0, 0);
790 	r = block(RS, r, bcon(4), INT, 0, 0);
791 	r = block(LS, r, bcon(4), INT, 0, 0);
792 
793 	t->n_type = p->n_type;
794 	ecomp(buildtree(ASSIGN, t, r));
795 }
796 
797 /*
798  * Print out a string of characters.
799  * Unfortunately, this code assumes that the assembler understands
800  * C-style escape sequences. (which it doesn't!)
801  * Location is already set.
802  */
803 void
804 instring(struct symtab *sp)
805 {
806 	char *s, *str = sp->sname;
807 
808 #if defined(ELFABI)
809 
810 	defloc(sp);
811 
812 #elif defined(MACHOABI)
813 
814 	extern int lastloc;
815 	if (lastloc != STRNG)
816 		printf("	.cstring\n");
817 	lastloc = STRNG;
818 	printf("\t.p2align 2\n");
819 	printf(LABFMT ":\n", sp->soffset);
820 
821 #endif
822 
823 	/* be kind to assemblers and avoid long strings */
824 	printf("\t.ascii \"");
825 	for (s = str; *s != 0; ) {
826 		if (*s++ == '\\') {
827 			(void)esccon(&s);
828 		}
829 		if (s - str > 64) {
830 			fwrite(str, 1, s - str, stdout);
831 			printf("\"\n\t.ascii \"");
832 			str = s;
833 		}
834 	}
835 	fwrite(str, 1, s - str, stdout);
836 	printf("\\0\"\n");
837 }
838 
839 /*
840  * print out a constant node, may be associated with a label.
841  * Do not free the node after use.
842  * off is bit offset from the beginning of the aggregate
843  * fsz is the number of bits this is referring to
844  */
845 int
846 ninval(CONSZ off, int fsz, NODE *p)
847 {
848 	union { float f; double d; long double l; int i[3]; } u;
849 	struct symtab *q;
850 	char *c;
851 	TWORD t;
852 	int i;
853 
854 	t = p->n_type;
855 	if (t > BTMASK)
856 		p->n_type = t = INT; /* pointer */
857 
858 
859 	if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) {
860 		if (p->n_op == UMUL)
861 			p = p->n_left;
862 		p = p->n_right;
863 		q = p->n_sp;
864 
865 #if defined(ELFABI)
866 
867 		if (q->soname && (c = strstr(q->soname, "@got(31)")) != NULL)
868 			*c = 0; /* ignore GOT ref here */
869 
870 #elif defined(MACHOABI)
871 
872 		if  ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) {
873 			q->soname++;	/* skip "L" */
874 			*c = 0; /* ignore GOT ref here */
875 		}
876 		else if ((c = strstr(q->soname, "-L")) != NULL)
877 			*c = 0; /* ignore GOT ref here */
878 
879 #endif
880 
881 	}
882 
883 	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
884 		uerror("element not constant");
885 
886 	switch (t) {
887 	case LONGLONG:
888 	case ULONGLONG:
889 #if 0
890 		/* little-endian */
891 		i = (p->n_lval >> 32);
892 		p->n_lval &= 0xffffffff;
893 		p->n_type = INT;
894 		ninval(off, 32, p);
895 		p->n_lval = i;
896 		ninval(off+32, 32, p);
897 #endif
898 		/* big-endian */
899 		i = (p->n_lval & 0xffffffff);
900 		p->n_lval >>= 32;
901 		p->n_type = INT;
902 		ninval(off, 32, p);
903 		p->n_lval = i;
904 		ninval(off+32, 32, p);
905 
906 		break;
907 	case INT:
908 	case UNSIGNED:
909 		printf("\t.long %d", (int)p->n_lval);
910 		if ((q = p->n_sp) != NULL) {
911 			if ((q->sclass == STATIC && q->slevel > 0)) {
912 				printf("+" LABFMT, q->soffset);
913 			} else {
914 				char *name = q->soname ? q->soname : exname(q->sname);
915 				printf("+%s", name);
916 			}
917 		}
918 		printf("\n");
919 		break;
920 	case LDOUBLE:
921 		u.i[2] = 0;
922 		u.l = (long double)p->n_dcon;
923 #if 0
924 		/* little-endian */
925 		printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
926 #endif
927 		/* big-endian */
928 		printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
929 		break;
930 	case DOUBLE:
931 		u.d = (double)p->n_dcon;
932 		printf("\t.long 0x%x\n\t.long 0x%x\n", u.i[0], u.i[1]);
933 		break;
934 	case FLOAT:
935 		u.f = (float)p->n_dcon;
936 		printf("\t.long 0x%x\n", u.i[0]);
937 		break;
938 	default:
939 		return 0;
940 	}
941 	return 1;
942 }
943 
944 /* make a name look like an external name in the local machine */
945 char *
946 exname(char *p)
947 {
948 #if defined(ELFABI)
949 
950 	return (p == NULL ? "" : p);
951 
952 #elif defined(MACHOABI)
953 
954 #define NCHNAM	256
955         static char text[NCHNAM+1];
956 	int i;
957 
958 	if (p == NULL)
959 		return "";
960 
961         text[0] = '_';
962         for (i=1; *p && i<NCHNAM; ++i)
963                 text[i] = *p++;
964 
965         text[i] = '\0';
966         text[NCHNAM] = '\0';  /* truncate */
967 
968         return (text);
969 
970 #endif
971 }
972 
973 /*
974  * map types which are not defined on the local machine
975  */
976 TWORD
977 ctype(TWORD type)
978 {
979 	switch (BTYPE(type)) {
980 	case LONG:
981 		MODTYPE(type,INT);
982 		break;
983 
984 	case ULONG:
985 		MODTYPE(type,UNSIGNED);
986 
987 	}
988 	return (type);
989 }
990 
991 void
992 calldec(NODE *p, NODE *q)
993 {
994 #ifdef PCC_DEBUG
995 	if (xdebug)
996 		printf("calldec:\n");
997 #endif
998 }
999 
1000 void
1001 extdec(struct symtab *q)
1002 {
1003 #ifdef PCC_DEBUG
1004 	if (xdebug)
1005 		printf("extdec:\n");
1006 #endif
1007 }
1008 
1009 /* make a common declaration for id, if reasonable */
1010 void
1011 defzero(struct symtab *sp)
1012 {
1013 	char *n;
1014 	int off;
1015 
1016 	off = tsize(sp->stype, sp->sdf, sp->sap);
1017 	off = (off+(SZCHAR-1))/SZCHAR;
1018 	printf("\t.%scomm ", sp->sclass == STATIC ? "l" : "");
1019 	n = sp->soname ? sp->soname : exname(sp->sname);
1020 	if (sp->slevel == 0)
1021 		printf("%s,%d\n", n, off);
1022 	else
1023 		printf(LABFMT ",%d\n", sp->soffset, off);
1024 }
1025 
1026 
1027 #ifdef notdef
1028 /* make a common declaration for id, if reasonable */
1029 void
1030 commdec(struct symtab *q)
1031 {
1032 	int off;
1033 
1034 	off = tsize(q->stype, q->sdf, q->ssue);
1035 	off = (off+(SZCHAR-1))/SZCHAR;
1036 	printf("\t.comm %s,0%o\n", q->soname ? q->soname : exname(q->sname), off);
1037 }
1038 
1039 /* make a local common declaration for id, if reasonable */
1040 void
1041 lcommdec(struct symtab *q)
1042 {
1043 	int off;
1044 
1045 	off = tsize(q->stype, q->sdf, q->ssue);
1046 	off = (off+(SZCHAR-1))/SZCHAR;
1047 	if (q->slevel == 0)
1048 		printf("\t.lcomm %s,%d\n", q->soname ? q->soname : exname(q->sname), off);
1049 	else
1050 		printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
1051 }
1052 
1053 /*
1054  * print a (non-prog) label.
1055  */
1056 void
1057 deflab1(int label)
1058 {
1059 	printf(LABFMT ":\n", label);
1060 }
1061 
1062 #if defined(ELFABI)
1063 
1064 static char *loctbl[] = { "text", "data", "section .rodata,",
1065     "section .rodata" };
1066 
1067 #elif defined(MACHOABI)
1068 
1069 static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" };
1070 
1071 #endif
1072 
1073 void
1074 setloc1(int locc)
1075 {
1076 #ifdef PCC_DEBUG
1077 	if (xdebug)
1078 		printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc);
1079 #endif
1080 
1081 	if (locc == lastloc)
1082 		return;
1083 	lastloc = locc;
1084 	printf("	.%s\n", loctbl[locc]);
1085 }
1086 #endif
1087 
1088 /* simulate and optimise the MOD opcode */
1089 static void
1090 simmod(NODE *p)
1091 {
1092 	NODE *r = p->n_right;
1093 
1094 	assert(p->n_op == MOD);
1095 
1096 	if (!ISUNSIGNED(p->n_type))
1097 		return;
1098 
1099 #define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0))
1100 
1101 	/* if the right is a constant power of two, then replace with AND */
1102 	if (r->n_op == ICON && ISPOW2(r->n_lval)) {
1103 		p->n_op = AND;
1104 		r->n_lval--;
1105 		return;
1106 	}
1107 
1108 #undef ISPOW2
1109 
1110 	/* other optimizations can go here */
1111 }
1112 
1113 static int constructor;
1114 static int destructor;
1115 
1116 /*
1117  * Give target the opportunity of handling pragmas.
1118  */
1119 int
1120 mypragma(char *str)
1121 {
1122 	if (strcmp(str, "tls") == 0) {
1123 		uerror("thread-local storage not supported for this target");
1124 		return 1;
1125 	}
1126 	if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
1127 		constructor = 1;
1128 		return 1;
1129 	}
1130 	if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
1131 		destructor = 1;
1132 		return 1;
1133 	}
1134 
1135 	return 0;
1136 }
1137 
1138 /*
1139  * Called when a identifier has been declared, to give target last word.
1140  */
1141 void
1142 fixdef(struct symtab *sp)
1143 {
1144 	/* may have sanity checks here */
1145 	if ((constructor || destructor) && (sp->sclass != PARAM)) {
1146 #ifdef MACHOABI
1147 		if (kflag) {
1148 			if (constructor)
1149 				printf("\t.mod_init_func\n");
1150 			else
1151 				printf("\t.mod_term_func\n");
1152 		} else {
1153 			if (constructor)
1154 				printf("\t.constructor\n");
1155 			else
1156 				printf("\t.destructor\n");
1157 		}
1158 		printf("\t.p2align 2\n");
1159 		printf("\t.long %s\n", exname(sp->sname));
1160 		printf("\t.text\n");
1161 		constructor = destructor = 0;
1162 #endif
1163 	}
1164 }
1165 
1166 /*
1167  * There is very little different here to the standard builtins.
1168  * It basically handles promotion of types smaller than INT.
1169  */
1170 
1171 NODE *
1172 powerpc_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
1173 {
1174         NODE *p, *q;
1175         int sz = 1;
1176 
1177         /* check num args and type */
1178         if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
1179             !ISPTR(a->n_left->n_type))
1180                 goto bad;
1181 
1182         /* must first deal with argument size; use int size */
1183         p = a->n_right;
1184         if (p->n_type < INT) {
1185                 /* round up to word */
1186                 sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
1187         }
1188 
1189         p = buildtree(ADDROF, p, NIL);  /* address of last arg */
1190         p = optim(buildtree(PLUS, p, bcon(sz)));
1191         q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
1192         q = buildtree(CAST, q, p);
1193         p = q->n_right;
1194         nfree(q->n_left);
1195         nfree(q);
1196         p = buildtree(ASSIGN, a->n_left, p);
1197         tfree(f);
1198         nfree(a);
1199 
1200         return p;
1201 
1202 bad:
1203         uerror("bad argument to __builtin_stdarg_start");
1204         return bcon(0);
1205 }
1206 
1207 NODE *
1208 powerpc_builtin_va_arg(NODE *f, NODE *a, TWORD t)
1209 {
1210         NODE *p, *q, *r;
1211         int sz, tmpnr;
1212 
1213         /* check num args and type */
1214         if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
1215             !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
1216                 goto bad;
1217 
1218         r = a->n_right;
1219 
1220         /* get type size */
1221         sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
1222         if (sz < SZINT/SZCHAR) {
1223                 werror("%s%s promoted to int when passed through ...",
1224                         ISUNSIGNED(r->n_type) ? "unsigned " : "",
1225                         DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
1226                 sz = SZINT/SZCHAR;
1227 		r->n_type = INT;
1228 		r->n_ap = 0;
1229         }
1230 
1231         p = tcopy(a->n_left);
1232 
1233 #if defined(ELFABI)
1234 
1235         /* alignment */
1236         if (SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
1237                 p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
1238                 p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap);
1239         }
1240 
1241 #endif
1242 
1243         /* create a copy to a temp node */
1244         q = tempnode(0, p->n_type, p->n_df, p->n_ap);
1245         tmpnr = regno(q);
1246         p = buildtree(ASSIGN, q, p);
1247 
1248         q = tempnode(tmpnr, p->n_type, p->n_df, p->n_ap);
1249         q = buildtree(PLUS, q, bcon(sz));
1250         q = buildtree(ASSIGN, a->n_left, q);
1251 
1252         q = buildtree(COMOP, p, q);
1253 
1254         nfree(a->n_right);
1255         nfree(a);
1256         nfree(f);
1257 
1258         p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
1259         p = buildtree(UMUL, p, NIL);
1260         p = buildtree(COMOP, q, p);
1261 
1262         return p;
1263 
1264 bad:
1265         uerror("bad argument to __builtin_va_arg");
1266         return bcon(0);
1267 }
1268 
1269 NODE *
1270 powerpc_builtin_va_end(NODE *f, NODE *a, TWORD t)
1271 {
1272         tfree(f);
1273         tfree(a);
1274 
1275         return bcon(0);
1276 }
1277 
1278 NODE *
1279 powerpc_builtin_va_copy(NODE *f, NODE *a, TWORD t)
1280 {
1281         if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
1282                 goto bad;
1283         tfree(f);
1284         f = buildtree(ASSIGN, a->n_left, a->n_right);
1285         nfree(a);
1286         return f;
1287 
1288 bad:
1289         uerror("bad argument to __buildtin_va_copy");
1290         return bcon(0);
1291 }
1292 
1293 NODE *
1294 powerpc_builtin_return_address(NODE *f, NODE *a, TWORD t)
1295 {
1296 	int nframes;
1297 	int i = 0;
1298 
1299 	if (a == NULL || a->n_op != ICON)
1300 		goto bad;
1301 
1302 	nframes = a->n_lval;
1303 
1304 	tfree(f);
1305 	tfree(a);
1306 
1307 	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1308 	regno(f) = SPREG;
1309 
1310 	do {
1311 		f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1312 	} while (i++ < nframes);
1313 
1314 	f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
1315 	f = buildtree(UMUL, f, NIL);
1316 
1317 	return f;
1318 bad:
1319         uerror("bad argument to __builtin_return_address");
1320         return bcon(0);
1321 }
1322 
1323 NODE *
1324 powerpc_builtin_frame_address(NODE *f, NODE *a, TWORD t)
1325 {
1326 	int nframes;
1327 	int i = 0;
1328 
1329 	if (a == NULL || a->n_op != ICON)
1330 		goto bad;
1331 
1332 	nframes = a->n_lval;
1333 
1334 	tfree(f);
1335 	tfree(a);
1336 
1337 	if (nframes == 0) {
1338 		f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1339 		regno(f) = FPREG;
1340 	} else {
1341 		f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1342 		regno(f) = SPREG;
1343 		do {
1344 			f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1345 		} while (i++ < nframes);
1346 		f = block(PLUS, f, bcon(24), INCREF(PTR+VOID), 0, 0);
1347 		f = buildtree(UMUL, f, NIL);
1348 	}
1349 
1350 	return f;
1351 bad:
1352         uerror("bad argument to __builtin_frame_address");
1353         return bcon(0);
1354 }
1355 
1356 void
1357 pass1_lastchance(struct interpass *ip)
1358 {
1359 }
1360