* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / arch / mips / local.c
blobd959c0da51884900f70d0e290b2c5b795c39b54c
1 /* $Id: local.c,v 1.24 2011/01/21 21:47:58 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
31 * Simon Olsson (simols-1@student.ltu.se) 2005.
34 #include <assert.h>
35 #include "pass1.h"
37 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
39 static int inbits, inval;
41 /* this is called to do local transformations on
42 * an expression tree preparitory to its being
43 * written out in intermediate code.
45 NODE *
46 clocal(NODE *p)
48 struct symtab *q;
49 NODE *r, *l;
50 int o;
51 int m;
52 TWORD ty;
53 int tmpnr, isptrvoid = 0;
55 #ifdef PCC_DEBUG
56 if (xdebug) {
57 printf("clocal in: %p\n", p);
58 fwalk(p, eprint, 0);
60 #endif
62 switch (o = p->n_op) {
64 case UCALL:
65 case CALL:
66 case STCALL:
67 case USTCALL:
68 if (p->n_type == VOID)
69 break;
71 * if the function returns void*, ecode() invokes
72 * delvoid() to convert it to uchar*.
73 * We just let this happen on the ASSIGN to the temp,
74 * and cast the pointer back to void* on access
75 * from the temp.
77 if (p->n_type == PTR+VOID)
78 isptrvoid = 1;
79 r = tempnode(0, p->n_type, p->n_df, p->n_ap);
80 tmpnr = regno(r);
81 r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
83 p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
84 if (isptrvoid) {
85 p = block(PCONV, p, NIL, PTR+VOID,
86 p->n_df, MKAP(PTR+VOID));
88 p = buildtree(COMOP, r, p);
89 break;
91 case NAME:
92 if ((q = p->n_sp) == NULL)
93 return p; /* Nothing to care about */
95 switch (q->sclass) {
97 case PARAM:
98 case AUTO:
99 /* fake up a structure reference */
100 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
101 r->n_lval = 0;
102 r->n_rval = FP;
103 p = stref(block(STREF, r, p, 0, 0, 0));
104 break;
106 case STATIC:
107 if (q->slevel == 0)
108 break;
109 p->n_lval = 0;
110 p->n_sp = q;
111 break;
113 case REGISTER:
114 p->n_op = REG;
115 p->n_lval = 0;
116 p->n_rval = q->soffset;
117 break;
120 break;
122 case FUNARG:
123 /* Args smaller than int are given as int */
124 if (p->n_type != CHAR && p->n_type != UCHAR &&
125 p->n_type != SHORT && p->n_type != USHORT)
126 break;
127 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKAP(INT));
128 p->n_type = INT;
129 p->n_ap = MKAP(INT);
130 p->n_rval = SZINT;
131 break;
133 case CBRANCH:
134 l = p->n_left;
137 * Remove unnecessary conversion ops.
139 if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
140 if (coptype(l->n_op) != BITYPE)
141 break;
142 if (l->n_right->n_op == ICON) {
143 r = l->n_left->n_left;
144 if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
145 break;
146 /* Type must be correct */
147 ty = r->n_type;
148 nfree(l->n_left);
149 l->n_left = r;
150 l->n_type = ty;
151 l->n_right->n_type = ty;
153 #if 0
154 else if (l->n_right->n_op == SCONV &&
155 l->n_left->n_type == l->n_right->n_type) {
156 r = l->n_left->n_left;
157 nfree(l->n_left);
158 l->n_left = r;
159 r = l->n_right->n_left;
160 nfree(l->n_right);
161 l->n_right = r;
163 #endif
165 break;
167 case PCONV:
168 /* Remove redundant PCONV's. Be careful */
169 l = p->n_left;
170 if (l->n_op == ICON) {
171 l->n_lval = (unsigned)l->n_lval;
172 goto delp;
174 if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
175 /* float etc? */
176 p->n_left = block(SCONV, l, NIL,
177 UNSIGNED, 0, MKAP(UNSIGNED));
178 break;
180 /* if left is SCONV, cannot remove */
181 if (l->n_op == SCONV)
182 break;
184 /* avoid ADDROF TEMP */
185 if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
186 break;
188 /* if conversion to another pointer type, just remove */
189 if (p->n_type > BTMASK && l->n_type > BTMASK)
190 goto delp;
191 break;
193 delp: l->n_type = p->n_type;
194 l->n_qual = p->n_qual;
195 l->n_df = p->n_df;
196 l->n_ap = p->n_ap;
197 nfree(p);
198 p = l;
199 break;
201 case SCONV:
202 l = p->n_left;
204 if (p->n_type == l->n_type) {
205 nfree(p);
206 p = l;
207 break;
210 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
211 btattr[p->n_type].atypsz == btattr[l->n_type].atypsz) {
212 if (p->n_type != FLOAT && p->n_type != DOUBLE &&
213 l->n_type != FLOAT && l->n_type != DOUBLE &&
214 l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
215 if (l->n_op == NAME || l->n_op == UMUL ||
216 l->n_op == TEMP) {
217 l->n_type = p->n_type;
218 nfree(p);
219 p = l;
220 break;
225 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
226 coptype(l->n_op) == BITYPE) {
227 l->n_type = p->n_type;
228 nfree(p);
229 p = l;
232 if (DEUNSIGN(p->n_type) == SHORT &&
233 DEUNSIGN(l->n_type) == SHORT) {
234 nfree(p);
235 p = l;
238 /* convert float/double to int before to (u)char/(u)short */
239 if ((DEUNSIGN(p->n_type) == CHAR ||
240 DEUNSIGN(p->n_type) == SHORT) &&
241 (l->n_type == FLOAT || l->n_type == DOUBLE ||
242 l->n_type == LDOUBLE)) {
243 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
244 p->n_left->n_type = INT;
245 break;
248 /* convert (u)char/(u)short to int before float/double */
249 if ((p->n_type == FLOAT || p->n_type == DOUBLE ||
250 p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
251 DEUNSIGN(l->n_type) == SHORT)) {
252 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
253 p->n_left->n_type = INT;
254 break;
257 o = l->n_op;
258 m = p->n_type;
260 if (o == ICON) {
261 CONSZ val = l->n_lval;
263 if (!ISPTR(m)) /* Pointers don't need to be conv'd */
264 switch (m) {
265 case BOOL:
266 l->n_lval = l->n_lval != 0;
267 break;
268 case CHAR:
269 l->n_lval = (char)val;
270 break;
271 case UCHAR:
272 l->n_lval = val & 0377;
273 break;
274 case SHORT:
275 l->n_lval = (short)val;
276 break;
277 case USHORT:
278 l->n_lval = val & 0177777;
279 break;
280 case ULONG:
281 case UNSIGNED:
282 l->n_lval = val & 0xffffffff;
283 break;
284 case LONG:
285 case INT:
286 l->n_lval = (int)val;
287 break;
288 case LONGLONG:
289 l->n_lval = (long long)val;
290 break;
291 case ULONGLONG:
292 l->n_lval = val;
293 break;
294 case VOID:
295 break;
296 case LDOUBLE:
297 case DOUBLE:
298 case FLOAT:
299 l->n_op = FCON;
300 l->n_dcon = val;
301 break;
302 default:
303 cerror("unknown type %d", m);
305 l->n_type = m;
306 nfree(p);
307 p = l;
308 } else if (o == FCON) {
309 l->n_lval = l->n_dcon;
310 l->n_sp = NULL;
311 l->n_op = ICON;
312 l->n_type = m;
313 l->n_ap = MKAP(m);
314 nfree(p);
315 p = clocal(l);
317 break;
319 case MOD:
320 case DIV:
321 if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
322 break;
323 if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
324 break;
325 /* make it an int division by inserting conversions */
326 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKAP(INT));
327 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKAP(INT));
328 p = block(SCONV, p, NIL, p->n_type, 0, MKAP(p->n_type));
329 p->n_left->n_type = INT;
330 break;
332 case PMCONV:
333 case PVCONV:
334 if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
335 nfree(p);
336 p = buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right);
337 break;
339 case FORCE:
340 /* put return value in return reg */
341 p->n_op = ASSIGN;
342 p->n_right = p->n_left;
343 p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
344 p->n_left->n_rval = RETREG(p->n_type);
345 break;
348 #ifdef PCC_DEBUG
349 if (xdebug) {
350 printf("clocal out: %p\n", p);
351 fwalk(p, eprint, 0);
353 #endif
355 return(p);
358 void
359 myp2tree(NODE *p)
361 struct symtab *sp;
363 if (p->n_op != FCON)
364 return;
366 /* Write float constants to memory */
368 sp = IALLOC(sizeof(struct symtab));
369 sp->sclass = STATIC;
370 sp->sap = MKAP(p->n_type);
371 sp->slevel = 1; /* fake numeric label */
372 sp->soffset = getlab();
373 sp->sflags = 0;
374 sp->stype = p->n_type;
375 sp->squal = (CON >> TSHIFT);
377 defloc(sp);
378 ninval(0, sp->sap->atypsz, p);
380 p->n_op = NAME;
381 p->n_lval = 0;
382 p->n_sp = sp;
386 /*ARGSUSED*/
388 andable(NODE *p)
390 return(1); /* all names can have & taken on them */
394 * at the end of the arguments of a ftn, set the automatic offset
396 void
397 cendarg()
399 autooff = AUTOINIT;
403 * is an automatic variable of type t OK for a register variable
406 cisreg(TWORD t)
408 if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
409 return(1);
410 return 0; /* XXX - fix reg assignment in pftn.c */
414 * return a node, for structure references, which is suitable for
415 * being added to a pointer of type t, in order to be off bits offset
416 * into a structure
417 * t, d, and s are the type, dimension offset, and sizeoffset
418 * Be careful about only handling first-level pointers, the following
419 * indirections must be fullword.
421 NODE *
422 offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *sue)
424 NODE *p;
426 if (xdebug)
427 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
428 off, t, d, 0);
430 p = bcon(off/SZCHAR);
431 return p;
435 * Allocate off bits on the stack. p is a tree that when evaluated
436 * is the multiply count for off, t is a NAME node where to write
437 * the allocated address.
439 void
440 spalloc(NODE *t, NODE *p, OFFSZ off)
442 NODE *sp;
443 int nbytes = off / SZCHAR;
445 p = buildtree(MUL, p, bcon(nbytes));
446 p = buildtree(PLUS, p, bcon(7));
447 p = buildtree(AND, p, bcon(~7));
449 /* subtract the size from sp */
450 sp = block(REG, NIL, NIL, p->n_type, 0, 0);
451 sp->n_lval = 0;
452 sp->n_rval = SP;
453 ecomp(buildtree(MINUSEQ, sp, p));
455 /* save the address of sp */
456 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
457 sp->n_rval = SP;
458 t->n_type = sp->n_type;
459 ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
463 * print out a constant node
464 * mat be associated with a label
466 void
467 ninval(CONSZ off, int fsz, NODE *p)
469 union { float f; double d; int i[2]; } u;
470 struct symtab *q;
471 TWORD t;
472 #ifndef USE_GAS
473 int i, j;
474 #endif
476 t = p->n_type;
477 if (t > BTMASK)
478 t = INT; /* pointer */
480 if (p->n_op != ICON && p->n_op != FCON)
481 cerror("ninval: init node not constant");
483 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
484 uerror("element not constant");
486 switch (t) {
487 case LONGLONG:
488 case ULONGLONG:
489 #ifdef USE_GAS
490 printf("\t.dword %lld\n", (long long)p->n_lval);
491 #else
492 i = p->n_lval >> 32;
493 j = p->n_lval & 0xffffffff;
494 p->n_type = INT;
495 if (bigendian) {
496 p->n_lval = j;
497 ninval(off, 32, p);
498 p->n_lval = i;
499 ninval(off+32, 32, p);
500 } else {
501 p->n_lval = i;
502 ninval(off, 32, p);
503 p->n_lval = j;
504 ninval(off+32, 32, p);
506 #endif
507 break;
508 case BOOL:
509 if (p->n_lval > 1)
510 p->n_lval = p->n_lval != 0;
511 /* FALLTHROUGH */
512 case INT:
513 case UNSIGNED:
514 printf("\t.word " CONFMT, (CONSZ)p->n_lval);
515 if ((q = p->n_sp) != NULL) {
516 if ((q->sclass == STATIC && q->slevel > 0)) {
517 printf("+" LABFMT, q->soffset);
518 } else
519 printf("+%s",
520 q->soname ? q->soname : exname(q->sname));
522 printf("\n");
523 break;
524 case SHORT:
525 case USHORT:
526 printf("\t.half %d\n", (int)p->n_lval & 0xffff);
527 break;
528 case CHAR:
529 case UCHAR:
530 printf("\t.byte %d\n", (int)p->n_lval & 0xff);
531 break;
532 case LDOUBLE:
533 case DOUBLE:
534 u.d = (double)p->n_dcon;
535 if (bigendian) {
536 printf("\t.word\t%d\n", u.i[0]);
537 printf("\t.word\t%d\n", u.i[1]);
538 } else {
539 printf("\t.word\t%d\n", u.i[1]);
540 printf("\t.word\t%d\n", u.i[0]);
542 break;
543 case FLOAT:
544 u.f = (float)p->n_dcon;
545 printf("\t.word\t0x%x\n", u.i[0]);
546 break;
547 default:
548 cerror("ninval");
552 /* make a name look like an external name in the local machine */
553 char *
554 exname(char *p)
556 if (p == NULL)
557 return "";
558 return p;
562 * map types which are not defined on the local machine
564 TWORD
565 ctype(TWORD type)
567 switch (BTYPE(type)) {
568 case LONG:
569 MODTYPE(type,INT);
570 break;
572 case ULONG:
573 MODTYPE(type,UNSIGNED);
576 return (type);
579 /* curid is a variable which is defined but
580 * is not initialized (and not a function );
581 * This routine returns the storage class for an uninitialized declaration
584 noinit(void)
586 return(EXTERN);
589 void
590 calldec(NODE *p, NODE *q)
594 void
595 extdec(struct symtab *q)
600 * Print out a string of characters.
601 * Assume that the assembler understands C-style escape
602 * sequences.
604 void
605 instring(struct symtab *sp)
607 char *s, *str;
609 defloc(sp);
610 str = sp->sname;
612 /* be kind to assemblers and avoid long strings */
613 printf("\t.ascii \"");
614 for (s = str; *s != 0; ) {
615 if (*s++ == '\\') {
616 (void)esccon(&s);
618 if (s - str > 60) {
619 fwrite(str, 1, s - str, stdout);
620 printf("\"\n\t.ascii \"");
621 str = s;
624 fwrite(str, 1, s - str, stdout);
625 printf("\\0\"\n");
628 /* make a common declaration for id, if reasonable */
629 void
630 defzero(struct symtab *sp)
632 int off;
634 off = tsize(sp->stype, sp->sdf, sp->sap);
635 off = (off+(SZCHAR-1))/SZCHAR;
636 printf(" .%scomm ", sp->sclass == STATIC ? "l" : "");
637 if (sp->slevel == 0)
638 printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off);
639 else
640 printf(LABFMT ",0%o\n", sp->soffset, off);
644 #ifdef notdef
645 /* make a common declaration for id, if reasonable */
646 void
647 commdec(struct symtab *q)
649 int off;
651 off = tsize(q->stype, q->sdf, q->ssue);
652 off = (off+(SZCHAR-1))/SZCHAR;
654 printf(" .comm %s,%d\n", exname(q->soname), off);
657 /* make a local common declaration for id, if reasonable */
658 void
659 lcommdec(struct symtab *q)
661 int off;
663 off = tsize(q->stype, q->sdf, q->ssue);
664 off = (off+(SZCHAR-1))/SZCHAR;
665 if (q->slevel == 0)
666 printf("\t.lcomm %s,%d\n", exname(q->soname), off);
667 else
668 printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
672 * print a (non-prog) label.
674 void
675 deflab1(int label)
677 printf(LABFMT ":\n", label);
680 /* ro-text, rw-data, ro-data, ro-strings */
681 static char *loctbl[] = { "text", "data", "rdata", "rdata" };
683 void
684 setloc1(int locc)
686 if (locc == lastloc && locc != STRNG)
687 return;
688 if (locc == RDATA && lastloc == STRNG)
689 return;
691 if (locc != lastloc) {
692 lastloc = locc;
693 printf("\t.%s\n", loctbl[locc]);
696 if (locc == STRNG)
697 printf("\t.align 2\n");
699 #endif
702 * Initialize a bitfield.
704 void
705 infld(CONSZ off, int fsz, CONSZ val)
707 if (idebug)
708 printf("infld off %lld, fsz %d, val %lld inbits %d\n",
709 off, fsz, val, inbits);
710 val &= (1 << fsz)-1;
711 while (fsz + inbits >= SZCHAR) {
712 inval |= (val << inbits);
713 printf("\t.byte %d\n", inval & 255);
714 fsz -= (SZCHAR - inbits);
715 val >>= (SZCHAR - inbits);
716 inval = inbits = 0;
718 if (fsz) {
719 inval |= (val << inbits);
720 inbits += fsz;
725 * set fsz bits in sequence to zero.
727 void
728 zbits(OFFSZ off, int fsz)
730 int m;
732 if (idebug)
733 printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
734 if ((m = (inbits % SZCHAR))) {
735 m = SZCHAR - m;
736 if (fsz < m) {
737 inbits += fsz;
738 return;
739 } else {
740 fsz -= m;
741 printf("\t.byte %d\n", inval);
742 inval = inbits = 0;
745 if (fsz >= SZCHAR) {
746 printf("\t.zero %d\n", fsz/SZCHAR);
747 fsz -= (fsz/SZCHAR) * SZCHAR;
749 if (fsz) {
750 inval = 0;
751 inbits = fsz;
756 * va_start(ap, last) implementation.
758 * f is the NAME node for this builtin function.
759 * a is the argument list containing:
760 * CM
761 * ap last
763 * It turns out that this is easy on MIPS. Just write the
764 * argument registers to the stack in va_arg_start() and
765 * use the traditional method of walking the stackframe.
767 NODE *
768 mips_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
770 NODE *p, *q;
771 int sz = 1;
773 /* check num args and type */
774 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
775 !ISPTR(a->n_left->n_type))
776 goto bad;
778 /* must first deal with argument size; use int size */
779 p = a->n_right;
780 if (p->n_type < INT) {
781 /* round up to word */
782 sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
785 p = buildtree(ADDROF, p, NIL); /* address of last arg */
786 p = optim(buildtree(PLUS, p, bcon(sz)));
787 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
788 q = buildtree(CAST, q, p);
789 p = q->n_right;
790 nfree(q->n_left);
791 nfree(q);
792 p = buildtree(ASSIGN, a->n_left, p);
793 tfree(f);
794 nfree(a);
796 return p;
798 bad:
799 uerror("bad argument to __builtin_stdarg_start");
800 return bcon(0);
803 NODE *
804 mips_builtin_va_arg(NODE *f, NODE *a, TWORD t)
806 NODE *p, *q, *r;
807 int sz, tmpnr;
809 /* check num args and type */
810 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
811 !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
812 goto bad;
814 r = a->n_right;
816 /* get type size */
817 sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
818 if (sz < SZINT/SZCHAR) {
819 werror("%s%s promoted to int when passed through ...",
820 r->n_type & 1 ? "unsigned " : "",
821 DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
822 sz = SZINT/SZCHAR;
825 /* alignment */
826 p = tcopy(a->n_left);
827 if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
828 p = buildtree(PLUS, p, bcon(7));
829 p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap);
832 /* create a copy to a temp node */
833 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
834 tmpnr = regno(q);
835 p = buildtree(ASSIGN, q, p);
837 q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
838 q = buildtree(PLUS, q, bcon(sz));
839 q = buildtree(ASSIGN, a->n_left, q);
841 q = buildtree(COMOP, p, q);
843 nfree(a->n_right);
844 nfree(a);
845 nfree(f);
847 p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
848 p = buildtree(UMUL, p, NIL);
849 p = buildtree(COMOP, q, p);
851 return p;
853 bad:
854 uerror("bad argument to __builtin_va_arg");
855 return bcon(0);
858 NODE *
859 mips_builtin_va_end(NODE *f, NODE *a, TWORD t)
861 tfree(f);
862 tfree(a);
863 return bcon(0);
866 NODE *
867 mips_builtin_va_copy(NODE *f, NODE *a, TWORD t)
869 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
870 goto bad;
871 tfree(f);
872 f = buildtree(ASSIGN, a->n_left, a->n_right);
873 nfree(a);
874 return f;
876 bad:
877 uerror("bad argument to __buildtin_va_copy");
878 return bcon(0);
881 static int constructor;
882 static int destructor;
885 * Give target the opportunity of handling pragmas.
888 mypragma(char *str)
891 if (strcmp(str, "tls") == 0) {
892 uerror("thread-local storage not supported for this target");
893 return 1;
895 if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
896 constructor = 1;
897 return 1;
899 if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
900 destructor = 1;
901 return 1;
904 return 0;
908 * Called when a identifier has been declared, to give target last word.
910 void
911 fixdef(struct symtab *sp)
913 if ((constructor || destructor) && (sp->sclass != PARAM)) {
914 printf("\t.section .%ctors,\"aw\",@progbits\n",
915 constructor ? 'c' : 'd');
916 printf("\t.p2align 2\n");
917 printf("\t.long %s\n", exname(sp->sname));
918 printf("\t.previous\n");
919 constructor = destructor = 0;
923 void
924 pass1_lastchance(struct interpass *ip)