xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/mips/local.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
1 /*	Id: local.c,v 1.37 2015/12/31 16:21:57 ragge Exp 	*/
2 /*	$NetBSD: local.c,v 1.1.1.6 2016/02/09 20:28:21 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 /*
29  * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
30  * Simon Olsson (simols-1@student.ltu.se) 2005.
31  */
32 
33 #include "pass1.h"
34 
35 #ifndef LANG_CXX
36 #define NODE P1ND
37 #define ccopy p1tcopy
38 #define tcopy p1tcopy
39 #define tfree p1tfree
40 #define nfree p1nfree
41 #define fwalk p1fwalk
42 #define talloc p1alloc
43 #endif
44 
45 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
46 
47 /* this is called to do local transformations on
48  * an expression tree preparitory to its being
49  * written out in intermediate code.
50  */
51 NODE *
clocal(NODE * p)52 clocal(NODE *p)
53 {
54 	struct symtab *q;
55 	NODE *r, *l;
56 	int o;
57 	int m;
58 	TWORD ty;
59 	int tmpnr, isptrvoid = 0;
60 
61 #ifdef PCC_DEBUG
62 	if (xdebug) {
63 		printf("clocal in: %p\n", p);
64 		fwalk(p, eprint, 0);
65 	}
66 #endif
67 
68 	switch (o = p->n_op) {
69 
70 	case UCALL:
71 	case CALL:
72 	case STCALL:
73 	case USTCALL:
74 		if (p->n_type == VOID)
75 			break;
76 		/*
77 		 * if the function returns void*, ecode() invokes
78 		 * delvoid() to convert it to uchar*.
79 		 * We just let this happen on the ASSIGN to the temp,
80 		 * and cast the pointer back to void* on access
81 		 * from the temp.
82 		 */
83 		if (p->n_type == PTR+VOID)
84 			isptrvoid = 1;
85 		r = tempnode(0, p->n_type, p->n_df, p->n_ap);
86 		tmpnr = regno(r);
87 		r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
88 
89 		p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
90 		if (isptrvoid) {
91 			p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0);
92 		}
93 		p = buildtree(COMOP, r, p);
94 		break;
95 
96 	case NAME:
97 		if ((q = p->n_sp) == NULL)
98 			return p; /* Nothing to care about */
99 
100 		switch (q->sclass) {
101 
102 		case PARAM:
103 		case AUTO:
104 			/* fake up a structure reference */
105 			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
106 			slval(r, 0);
107 			r->n_rval = FP;
108 			p = stref(block(STREF, r, p, 0, 0, 0));
109 			break;
110 
111 		case STATIC:
112 			if (q->slevel == 0)
113 				break;
114 			slval(p, 0);
115 			p->n_sp = q;
116 			break;
117 
118 		case REGISTER:
119 			p->n_op = REG;
120 			slval(p, 0);
121 			p->n_rval = q->soffset;
122 			break;
123 
124 		}
125 		break;
126 
127 	case FUNARG:
128 		/* Args smaller than int are given as int */
129 		if (p->n_type != CHAR && p->n_type != UCHAR &&
130 		    p->n_type != SHORT && p->n_type != USHORT)
131 			break;
132 		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
133 		p->n_type = INT;
134 		p->n_ap = 0;
135 		p->n_rval = SZINT;
136 		break;
137 
138 	case CBRANCH:
139 		l = p->n_left;
140 
141 		/*
142 		 * Remove unnecessary conversion ops.
143 		 */
144 		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
145 			if (coptype(l->n_op) != BITYPE)
146 				break;
147 			if (l->n_right->n_op == ICON) {
148 				r = l->n_left->n_left;
149 				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
150 					break;
151 				/* Type must be correct */
152 				ty = r->n_type;
153 				nfree(l->n_left);
154 				l->n_left = r;
155 				l->n_type = ty;
156 				l->n_right->n_type = ty;
157 			}
158 #if 0
159 			  else if (l->n_right->n_op == SCONV &&
160 			    l->n_left->n_type == l->n_right->n_type) {
161 				r = l->n_left->n_left;
162 				nfree(l->n_left);
163 				l->n_left = r;
164 				r = l->n_right->n_left;
165 				nfree(l->n_right);
166 				l->n_right = r;
167 			}
168 #endif
169 		}
170 		break;
171 
172 	case PCONV:
173 		/* Remove redundant PCONV's. Be careful */
174 		l = p->n_left;
175 		if (l->n_op == ICON) {
176 			slval(l, (unsigned)glval(l));
177 			goto delp;
178 		}
179 		if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
180 			/* float etc? */
181 			p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
182 			break;
183 		}
184 		/* if left is SCONV, cannot remove */
185 		if (l->n_op == SCONV)
186 			break;
187 
188 		/* avoid ADDROF TEMP */
189 		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
190 			break;
191 
192 		/* if conversion to another pointer type, just remove */
193 		if (p->n_type > BTMASK && l->n_type > BTMASK)
194 			goto delp;
195 		break;
196 
197 	delp:	l->n_type = p->n_type;
198 		l->n_qual = p->n_qual;
199 		l->n_df = p->n_df;
200 		l->n_ap = p->n_ap;
201 		nfree(p);
202 		p = l;
203 		break;
204 
205 	case SCONV:
206 		l = p->n_left;
207 
208 		if (p->n_type == l->n_type) {
209 			nfree(p);
210 			p = l;
211 			break;
212 		}
213 
214 		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
215 		    tsize(p->n_type, p->n_df, p->n_ap) ==
216 		    tsize(l->n_type, l->n_df, l->n_ap)) {
217 			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
218 			    l->n_type != FLOAT && l->n_type != DOUBLE &&
219 			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
220 				if (l->n_op == NAME || l->n_op == UMUL ||
221 				    l->n_op == TEMP) {
222 					l->n_type = p->n_type;
223 					nfree(p);
224 					p = l;
225 					break;
226 				}
227 			}
228 		}
229 
230 		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
231 		    coptype(l->n_op) == BITYPE) {
232 			l->n_type = p->n_type;
233 			nfree(p);
234 			p = l;
235 		}
236 
237 		if (DEUNSIGN(p->n_type) == SHORT &&
238 		    DEUNSIGN(l->n_type) == SHORT) {
239 			nfree(p);
240 			p = l;
241 		}
242 
243 		/* convert float/double to int before to (u)char/(u)short */
244 		if ((DEUNSIGN(p->n_type) == CHAR ||
245 		    DEUNSIGN(p->n_type) == SHORT) &&
246                     (l->n_type == FLOAT || l->n_type == DOUBLE ||
247 		    l->n_type == LDOUBLE)) {
248 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
249 			p->n_left->n_type = INT;
250 			break;
251                 }
252 
253 		/* convert (u)char/(u)short to int before float/double */
254 		if  ((p->n_type == FLOAT || p->n_type == DOUBLE ||
255 		    p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
256 		    DEUNSIGN(l->n_type) == SHORT)) {
257 			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
258 			p->n_left->n_type = INT;
259 			break;
260                 }
261 
262 		o = l->n_op;
263 		m = p->n_type;
264 
265 		if (o == ICON) {
266 			CONSZ val = glval(l);
267 
268 			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
269 			    switch (m) {
270 			case BOOL:
271 				val = nncon(l) ? (val != 0) : 1;
272 				slval(l, val);
273 				l->n_sp = NULL;
274 				break;
275 			case CHAR:
276 				slval(l, (char)val);
277 				break;
278 			case UCHAR:
279 				slval(l, val & 0377);
280 				break;
281 			case SHORT:
282 				slval(l, (short)val);
283 				break;
284 			case USHORT:
285 				slval(l, val & 0177777);
286 				break;
287 			case ULONG:
288 			case UNSIGNED:
289 				slval(l, val & 0xffffffff);
290 				break;
291 			case LONG:
292 			case INT:
293 				slval(l, (int)val);
294 				break;
295 			case LONGLONG:
296 				slval(l, (long long)val);
297 				break;
298 			case ULONGLONG:
299 				slval(l, val);
300 				break;
301 			case VOID:
302 				break;
303 			case LDOUBLE:
304 			case DOUBLE:
305 			case FLOAT:
306 				l->n_op = FCON;
307 				l->n_dcon = tmpalloc(sizeof(union flt));
308 				((union flt *)l->n_dcon)->fp = val;
309 				break;
310 			default:
311 				cerror("unknown type %d", m);
312 			}
313 			l->n_type = m;
314 			nfree(p);
315 			p = l;
316 		} else if (o == FCON) {
317 			CONSZ lv;
318 			if (p->n_type == BOOL)
319 				lv = !FLOAT_ISZERO(((union flt *)l->n_dcon));
320 			else {
321 				FLOAT_FP2INT(lv, ((union flt *)l->n_dcon), m);
322 			}
323 			slval(l, lv);
324 			l->n_sp = NULL;
325 			l->n_op = ICON;
326 			l->n_type = m;
327 			l->n_ap = 0;
328 			nfree(p);
329 			p = clocal(l);
330 		}
331 		break;
332 
333 	case MOD:
334 	case DIV:
335 		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
336 			break;
337 		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
338 			break;
339 		/* make it an int division by inserting conversions */
340 		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
341 		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
342 		p = block(SCONV, p, NIL, p->n_type, 0, 0);
343 		p->n_left->n_type = INT;
344 		break;
345 
346 	case FORCE:
347 		/* put return value in return reg */
348 		p->n_op = ASSIGN;
349 		p->n_right = p->n_left;
350 		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
351 		p->n_left->n_rval = RETREG(p->n_type);
352 		break;
353 	}
354 
355 #ifdef PCC_DEBUG
356 	if (xdebug) {
357 		printf("clocal out: %p\n", p);
358 		fwalk(p, eprint, 0);
359 	}
360 #endif
361 
362 	return(p);
363 }
364 
365 void
myp2tree(NODE * p)366 myp2tree(NODE *p)
367 {
368 	struct symtab *sp;
369 
370 	if (p->n_op != FCON)
371 		return;
372 
373 	/* Write float constants to memory */
374 
375 	sp = IALLOC(sizeof(struct symtab));
376 	sp->sclass = STATIC;
377 	sp->sap = 0;
378 	sp->slevel = 1; /* fake numeric label */
379 	sp->soffset = getlab();
380 	sp->sflags = 0;
381 	sp->stype = p->n_type;
382 	sp->squal = (CON >> TSHIFT);
383 
384 	defloc(sp);
385 	ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
386 
387 	p->n_op = NAME;
388 	slval(p, 0);
389 	p->n_sp = sp;
390 
391 }
392 
393 /*ARGSUSED*/
394 int
andable(NODE * p)395 andable(NODE *p)
396 {
397 	return(1);  /* all names can have & taken on them */
398 }
399 
400 /*
401  * is an automatic variable of type t OK for a register variable
402  */
403 int
cisreg(TWORD t)404 cisreg(TWORD t)
405 {
406 	if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
407 		return(1);
408 	return 0; /* XXX - fix reg assignment in pftn.c */
409 }
410 
411 /*
412  * Allocate off bits on the stack.  p is a tree that when evaluated
413  * is the multiply count for off, t is a NAME node where to write
414  * the allocated address.
415  */
416 void
spalloc(NODE * t,NODE * p,OFFSZ off)417 spalloc(NODE *t, NODE *p, OFFSZ off)
418 {
419 	NODE *sp;
420 	int nbytes = off / SZCHAR;
421 
422 	p = buildtree(MUL, p, bcon(nbytes));
423 	p = buildtree(PLUS, p, bcon(7));
424 	p = buildtree(AND, p, bcon(~7));
425 
426 	/* subtract the size from sp */
427 	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
428 	slval(sp, 0);
429 	sp->n_rval = SP;
430 	ecomp(buildtree(MINUSEQ, sp, p));
431 
432 	/* save the address of sp */
433 	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
434 	sp->n_rval = SP;
435 	t->n_type = sp->n_type;
436 	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
437 }
438 
439 /*
440  * print out a constant node
441  * mat be associated with a label
442  */
443 int
ninval(CONSZ off,int fsz,NODE * p)444 ninval(CONSZ off, int fsz, NODE *p)
445 {
446         union { float f; double d; int i[2]; } u;
447         struct symtab *q;
448         TWORD t;
449 #ifndef USE_GAS
450         int i, j;
451 #endif
452 
453         t = p->n_type;
454         if (t > BTMASK)
455 		p->n_type = t = INT; /* pointer */
456 
457         if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
458                 uerror("element not constant");
459 
460         switch (t) {
461         case LONGLONG:
462         case ULONGLONG:
463 #ifdef USE_GAS
464                 printf("\t.dword %lld\n", (long long)glval(p));
465 #else
466 		i = glval(p) >> 32;
467                 j = glval(p) & 0xffffffff;
468                 p->n_type = INT;
469 		if (bigendian) {
470 			slval(p, j);
471 	                ninval(off, 32, p);
472 			slval(p, i);
473 			ninval(off+32, 32, p);
474 		} else {
475 			slval(p, i);
476 	                ninval(off, 32, p);
477 			slval(p, j);
478 			ninval(off+32, 32, p);
479 		}
480 #endif
481                 break;
482         case INT:
483         case UNSIGNED:
484                 printf("\t.word " CONFMT, (CONSZ)glval(p));
485                 if ((q = p->n_sp) != NULL) {
486                         if ((q->sclass == STATIC && q->slevel > 0)) {
487                                 printf("+" LABFMT, q->soffset);
488                         } else
489                                 printf("+%s", getexname(q));
490                 }
491                 printf("\n");
492                 break;
493         case SHORT:
494         case USHORT:
495 		astypnames[SHORT] = astypnames[USHORT] = "\t.half";
496                 return 0;
497         case LDOUBLE:
498         case DOUBLE:
499                 u.d = (double)((union flt *)p->n_dcon)->fp;
500 		if (bigendian) {
501 	                printf("\t.word\t%d\n", u.i[0]);
502 			printf("\t.word\t%d\n", u.i[1]);
503 		} else {
504 			printf("\t.word\t%d\n", u.i[1]);
505 	                printf("\t.word\t%d\n", u.i[0]);
506 		}
507                 break;
508         case FLOAT:
509                 u.f = (float)((union flt *)p->n_dcon)->fp;
510                 printf("\t.word\t0x%x\n", u.i[0]);
511                 break;
512         default:
513                 return 0;
514         }
515 	return 1;
516 }
517 
518 /* make a name look like an external name in the local machine */
519 char *
exname(char * p)520 exname(char *p)
521 {
522 	if (p == NULL)
523 		return "";
524 	return p;
525 }
526 
527 /*
528  * map types which are not defined on the local machine
529  */
530 TWORD
ctype(TWORD type)531 ctype(TWORD type)
532 {
533 	switch (BTYPE(type)) {
534 	case LONG:
535 		MODTYPE(type,INT);
536 		break;
537 
538 	case ULONG:
539 		MODTYPE(type,UNSIGNED);
540 
541 	}
542 	return (type);
543 }
544 
545 void
calldec(NODE * p,NODE * q)546 calldec(NODE *p, NODE *q)
547 {
548 }
549 
550 void
extdec(struct symtab * q)551 extdec(struct symtab *q)
552 {
553 }
554 
555 /* make a common declaration for id, if reasonable */
556 void
defzero(struct symtab * sp)557 defzero(struct symtab *sp)
558 {
559 	int off;
560 
561 	off = tsize(sp->stype, sp->sdf, sp->sap);
562 	off = (off+(SZCHAR-1))/SZCHAR;
563 	printf("	.%scomm ", sp->sclass == STATIC ? "l" : "");
564 	if (sp->slevel == 0)
565 		printf("%s,0%o\n", getexname(sp), off);
566 	else
567 		printf(LABFMT ",0%o\n", sp->soffset, off);
568 }
569 
570 
571 #ifdef notdef
572 /* make a common declaration for id, if reasonable */
573 void
commdec(struct symtab * q)574 commdec(struct symtab *q)
575 {
576 	int off;
577 
578 	off = tsize(q->stype, q->sdf, q->ssue);
579 	off = (off+(SZCHAR-1))/SZCHAR;
580 
581 	printf("	.comm %s,%d\n", exname(q->soname), off);
582 }
583 
584 /* make a local common declaration for id, if reasonable */
585 void
lcommdec(struct symtab * q)586 lcommdec(struct symtab *q)
587 {
588 	int off;
589 
590 	off = tsize(q->stype, q->sdf, q->ssue);
591 	off = (off+(SZCHAR-1))/SZCHAR;
592 	if (q->slevel == 0)
593 		printf("\t.lcomm %s,%d\n", exname(q->soname), off);
594 	else
595 		printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
596 }
597 
598 /*
599  * print a (non-prog) label.
600  */
601 void
deflab1(int label)602 deflab1(int label)
603 {
604 	printf(LABFMT ":\n", label);
605 }
606 
607 /* ro-text, rw-data, ro-data, ro-strings */
608 static char *loctbl[] = { "text", "data", "rdata", "rdata" };
609 
610 void
setloc1(int locc)611 setloc1(int locc)
612 {
613 	if (locc == lastloc && locc != STRNG)
614 		return;
615 	if (locc == RDATA && lastloc == STRNG)
616 		return;
617 
618 	if (locc != lastloc) {
619 		lastloc = locc;
620 		printf("\t.%s\n", loctbl[locc]);
621 	}
622 
623 	if (locc == STRNG)
624 		printf("\t.align 2\n");
625 }
626 #endif
627 
628 /*
629  * va_start(ap, last) implementation.
630  *
631  * f is the NAME node for this builtin function.
632  * a is the argument list containing:
633  *	   CM
634  *	ap   last
635  *
636  * It turns out that this is easy on MIPS.  Just write the
637  * argument registers to the stack in va_arg_start() and
638  * use the traditional method of walking the stackframe.
639  */
640 NODE *
mips_builtin_stdarg_start(const struct bitable * bt,NODE * a)641 mips_builtin_stdarg_start(const struct bitable *bt, NODE *a)
642 {
643 	NODE *p, *q;
644 	int sz = 1;
645 
646 	/* check num args and type */
647 	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
648 	    !ISPTR(a->n_left->n_type))
649 		goto bad;
650 
651 	/* must first deal with argument size; use int size */
652 	p = a->n_right;
653 	if (p->n_type < INT) {
654 		/* round up to word */
655 		sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
656 	}
657 
658 	p = buildtree(ADDROF, p, NIL);	/* address of last arg */
659 	p = optim(buildtree(PLUS, p, bcon(sz)));
660 	q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
661 	q = buildtree(CAST, q, p);
662 	p = q->n_right;
663 	nfree(q->n_left);
664 	nfree(q);
665 	p = buildtree(ASSIGN, a->n_left, p);
666 	nfree(a);
667 
668 	return p;
669 
670 bad:
671 	uerror("bad argument to __builtin_stdarg_start");
672 	return bcon(0);
673 }
674 
675 NODE *
mips_builtin_va_arg(const struct bitable * bt,NODE * a)676 mips_builtin_va_arg(const struct bitable *bt, NODE *a)
677 {
678 	NODE *p, *q, *r;
679 	int sz, tmpnr;
680 
681 	/* check num args and type */
682 	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
683 	    !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
684 		goto bad;
685 
686 	r = a->n_right;
687 
688 	/* get type size */
689 	sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
690 	if (sz < SZINT/SZCHAR) {
691 		werror("%s%s promoted to int when passed through ...",
692 			r->n_type & 1 ? "unsigned " : "",
693 			DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
694 		sz = SZINT/SZCHAR;
695 	}
696 
697 	/* alignment */
698 	p = tcopy(a->n_left);
699 	if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
700 		p = buildtree(PLUS, p, bcon(7));
701 		p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap);
702 	}
703 
704 	/* create a copy to a temp node */
705 	q = tempnode(0, p->n_type, p->n_df, p->n_ap);
706 	tmpnr = regno(q);
707 	p = buildtree(ASSIGN, q, p);
708 
709 	q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
710 	q = buildtree(PLUS, q, bcon(sz));
711 	q = buildtree(ASSIGN, a->n_left, q);
712 
713 	q = buildtree(COMOP, p, q);
714 
715 	nfree(a->n_right);
716 	nfree(a);
717 
718 	p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
719 	p = buildtree(UMUL, p, NIL);
720 	p = buildtree(COMOP, q, p);
721 
722 	return p;
723 
724 bad:
725 	uerror("bad argument to __builtin_va_arg");
726 	return bcon(0);
727 }
728 
729 NODE *
mips_builtin_va_end(const struct bitable * bt,NODE * a)730 mips_builtin_va_end(const struct bitable *bt, NODE *a)
731 {
732 	tfree(a);
733 	return bcon(0);
734 }
735 
736 NODE *
mips_builtin_va_copy(const struct bitable * bt,NODE * a)737 mips_builtin_va_copy(const struct bitable *bt, NODE *a)
738 {
739 	NODE *f;
740 
741 	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
742 		goto bad;
743 	f = buildtree(ASSIGN, a->n_left, a->n_right);
744 	nfree(a);
745 	return f;
746 
747 bad:
748 	uerror("bad argument to __buildtin_va_copy");
749 	return bcon(0);
750 }
751 
752 static int constructor;
753 static int destructor;
754 
755 /*
756  * Give target the opportunity of handling pragmas.
757  */
758 int
mypragma(char * str)759 mypragma(char *str)
760 {
761 
762 	if (strcmp(str, "tls") == 0) {
763 		uerror("thread-local storage not supported for this target");
764 		return 1;
765 	}
766 	if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
767 		constructor = 1;
768 		return 1;
769 	}
770 	if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
771 		destructor = 1;
772 		return 1;
773 	}
774 
775 	return 0;
776 }
777 
778 /*
779  * Called when a identifier has been declared, to give target last word.
780  */
781 void
fixdef(struct symtab * sp)782 fixdef(struct symtab *sp)
783 {
784 	if ((constructor || destructor) && (sp->sclass != PARAM)) {
785 		printf("\t.section .%ctors,\"aw\",@progbits\n",
786 		    constructor ? 'c' : 'd');
787 		printf("\t.p2align 2\n");
788 		printf("\t.long %s\n", exname(sp->sname));
789 		printf("\t.previous\n");
790 		constructor = destructor = 0;
791 	}
792 }
793 
794 void
pass1_lastchance(struct interpass * ip)795 pass1_lastchance(struct interpass *ip)
796 {
797 }
798