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