source: mainline/uspace/app/pcc/arch/mips/local.c@ a7de7182

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a7de7182 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 20.4 KB
Line 
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.
5 *
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
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
31 * Simon Olsson (simols-1@student.ltu.se) 2005.
32 */
33
34#include <assert.h>
35#include "pass1.h"
36
37#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
38
39static int inbits, inval;
40
41/* this is called to do local transformations on
42 * an expression tree preparitory to its being
43 * written out in intermediate code.
44 */
45NODE *
46clocal(NODE *p)
47{
48 struct symtab *q;
49 NODE *r, *l;
50 int o;
51 int m;
52 TWORD ty;
53 int tmpnr, isptrvoid = 0;
54
55#ifdef PCC_DEBUG
56 if (xdebug) {
57 printf("clocal in: %p\n", p);
58 fwalk(p, eprint, 0);
59 }
60#endif
61
62 switch (o = p->n_op) {
63
64 case UCALL:
65 case CALL:
66 case STCALL:
67 case USTCALL:
68 if (p->n_type == VOID)
69 break;
70 /*
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.
76 */
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);
82
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));
87 }
88 p = buildtree(COMOP, r, p);
89 break;
90
91 case NAME:
92 if ((q = p->n_sp) == NULL)
93 return p; /* Nothing to care about */
94
95 switch (q->sclass) {
96
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;
105
106 case STATIC:
107 if (q->slevel == 0)
108 break;
109 p->n_lval = 0;
110 p->n_sp = q;
111 break;
112
113 case REGISTER:
114 p->n_op = REG;
115 p->n_lval = 0;
116 p->n_rval = q->soffset;
117 break;
118
119 }
120 break;
121
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;
132
133 case CBRANCH:
134 l = p->n_left;
135
136 /*
137 * Remove unnecessary conversion ops.
138 */
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;
152 }
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;
162 }
163#endif
164 }
165 break;
166
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;
173 }
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;
179 }
180 /* if left is SCONV, cannot remove */
181 if (l->n_op == SCONV)
182 break;
183
184 /* avoid ADDROF TEMP */
185 if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
186 break;
187
188 /* if conversion to another pointer type, just remove */
189 if (p->n_type > BTMASK && l->n_type > BTMASK)
190 goto delp;
191 break;
192
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;
200
201 case SCONV:
202 l = p->n_left;
203
204 if (p->n_type == l->n_type) {
205 nfree(p);
206 p = l;
207 break;
208 }
209
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;
221 }
222 }
223 }
224
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;
230 }
231
232 if (DEUNSIGN(p->n_type) == SHORT &&
233 DEUNSIGN(l->n_type) == SHORT) {
234 nfree(p);
235 p = l;
236 }
237
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;
246 }
247
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;
255 }
256
257 o = l->n_op;
258 m = p->n_type;
259
260 if (o == ICON) {
261 CONSZ val = l->n_lval;
262
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);
304 }
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);
316 }
317 break;
318
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;
331
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;
338
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;
346 }
347
348#ifdef PCC_DEBUG
349 if (xdebug) {
350 printf("clocal out: %p\n", p);
351 fwalk(p, eprint, 0);
352 }
353#endif
354
355 return(p);
356}
357
358void
359myp2tree(NODE *p)
360{
361 struct symtab *sp;
362
363 if (p->n_op != FCON)
364 return;
365
366 /* Write float constants to memory */
367
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);
376
377 defloc(sp);
378 ninval(0, sp->sap->atypsz, p);
379
380 p->n_op = NAME;
381 p->n_lval = 0;
382 p->n_sp = sp;
383
384}
385
386/*ARGSUSED*/
387int
388andable(NODE *p)
389{
390 return(1); /* all names can have & taken on them */
391}
392
393/*
394 * at the end of the arguments of a ftn, set the automatic offset
395 */
396void
397cendarg()
398{
399 autooff = AUTOINIT;
400}
401
402/*
403 * is an automatic variable of type t OK for a register variable
404 */
405int
406cisreg(TWORD t)
407{
408 if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
409 return(1);
410 return 0; /* XXX - fix reg assignment in pftn.c */
411}
412
413/*
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.
420 */
421NODE *
422offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *sue)
423{
424 NODE *p;
425
426 if (xdebug)
427 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
428 off, t, d, 0);
429
430 p = bcon(off/SZCHAR);
431 return p;
432}
433
434/*
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.
438 */
439void
440spalloc(NODE *t, NODE *p, OFFSZ off)
441{
442 NODE *sp;
443 int nbytes = off / SZCHAR;
444
445 p = buildtree(MUL, p, bcon(nbytes));
446 p = buildtree(PLUS, p, bcon(7));
447 p = buildtree(AND, p, bcon(~7));
448
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));
454
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! */
460}
461
462/*
463 * print out a constant node
464 * mat be associated with a label
465 */
466void
467ninval(CONSZ off, int fsz, NODE *p)
468{
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
475
476 t = p->n_type;
477 if (t > BTMASK)
478 t = INT; /* pointer */
479
480 if (p->n_op != ICON && p->n_op != FCON)
481 cerror("ninval: init node not constant");
482
483 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
484 uerror("element not constant");
485
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);
505 }
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));
521 }
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]);
541 }
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");
549 }
550}
551
552/* make a name look like an external name in the local machine */
553char *
554exname(char *p)
555{
556 if (p == NULL)
557 return "";
558 return p;
559}
560
561/*
562 * map types which are not defined on the local machine
563 */
564TWORD
565ctype(TWORD type)
566{
567 switch (BTYPE(type)) {
568 case LONG:
569 MODTYPE(type,INT);
570 break;
571
572 case ULONG:
573 MODTYPE(type,UNSIGNED);
574
575 }
576 return (type);
577}
578
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
582 */
583int
584noinit(void)
585{
586 return(EXTERN);
587}
588
589void
590calldec(NODE *p, NODE *q)
591{
592}
593
594void
595extdec(struct symtab *q)
596{
597}
598
599/*
600 * Print out a string of characters.
601 * Assume that the assembler understands C-style escape
602 * sequences.
603 */
604void
605instring(struct symtab *sp)
606{
607 char *s, *str;
608
609 defloc(sp);
610 str = sp->sname;
611
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);
617 }
618 if (s - str > 60) {
619 fwrite(str, 1, s - str, stdout);
620 printf("\"\n\t.ascii \"");
621 str = s;
622 }
623 }
624 fwrite(str, 1, s - str, stdout);
625 printf("\\0\"\n");
626}
627
628/* make a common declaration for id, if reasonable */
629void
630defzero(struct symtab *sp)
631{
632 int off;
633
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);
641}
642
643
644#ifdef notdef
645/* make a common declaration for id, if reasonable */
646void
647commdec(struct symtab *q)
648{
649 int off;
650
651 off = tsize(q->stype, q->sdf, q->ssue);
652 off = (off+(SZCHAR-1))/SZCHAR;
653
654 printf(" .comm %s,%d\n", exname(q->soname), off);
655}
656
657/* make a local common declaration for id, if reasonable */
658void
659lcommdec(struct symtab *q)
660{
661 int off;
662
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);
669}
670
671/*
672 * print a (non-prog) label.
673 */
674void
675deflab1(int label)
676{
677 printf(LABFMT ":\n", label);
678}
679
680/* ro-text, rw-data, ro-data, ro-strings */
681static char *loctbl[] = { "text", "data", "rdata", "rdata" };
682
683void
684setloc1(int locc)
685{
686 if (locc == lastloc && locc != STRNG)
687 return;
688 if (locc == RDATA && lastloc == STRNG)
689 return;
690
691 if (locc != lastloc) {
692 lastloc = locc;
693 printf("\t.%s\n", loctbl[locc]);
694 }
695
696 if (locc == STRNG)
697 printf("\t.align 2\n");
698}
699#endif
700
701/*
702 * Initialize a bitfield.
703 */
704void
705infld(CONSZ off, int fsz, CONSZ val)
706{
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;
717 }
718 if (fsz) {
719 inval |= (val << inbits);
720 inbits += fsz;
721 }
722}
723
724/*
725 * set fsz bits in sequence to zero.
726 */
727void
728zbits(OFFSZ off, int fsz)
729{
730 int m;
731
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;
743 }
744 }
745 if (fsz >= SZCHAR) {
746 printf("\t.zero %d\n", fsz/SZCHAR);
747 fsz -= (fsz/SZCHAR) * SZCHAR;
748 }
749 if (fsz) {
750 inval = 0;
751 inbits = fsz;
752 }
753}
754
755/*
756 * va_start(ap, last) implementation.
757 *
758 * f is the NAME node for this builtin function.
759 * a is the argument list containing:
760 * CM
761 * ap last
762 *
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.
766 */
767NODE *
768mips_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
769{
770 NODE *p, *q;
771 int sz = 1;
772
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;
777
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);
783 }
784
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);
795
796 return p;
797
798bad:
799 uerror("bad argument to __builtin_stdarg_start");
800 return bcon(0);
801}
802
803NODE *
804mips_builtin_va_arg(NODE *f, NODE *a, TWORD t)
805{
806 NODE *p, *q, *r;
807 int sz, tmpnr;
808
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;
813
814 r = a->n_right;
815
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;
823 }
824
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);
830 }
831
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);
836
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);
840
841 q = buildtree(COMOP, p, q);
842
843 nfree(a->n_right);
844 nfree(a);
845 nfree(f);
846
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);
850
851 return p;
852
853bad:
854 uerror("bad argument to __builtin_va_arg");
855 return bcon(0);
856}
857
858NODE *
859mips_builtin_va_end(NODE *f, NODE *a, TWORD t)
860{
861 tfree(f);
862 tfree(a);
863 return bcon(0);
864}
865
866NODE *
867mips_builtin_va_copy(NODE *f, NODE *a, TWORD t)
868{
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;
875
876bad:
877 uerror("bad argument to __buildtin_va_copy");
878 return bcon(0);
879}
880
881static int constructor;
882static int destructor;
883
884/*
885 * Give target the opportunity of handling pragmas.
886 */
887int
888mypragma(char *str)
889{
890
891 if (strcmp(str, "tls") == 0) {
892 uerror("thread-local storage not supported for this target");
893 return 1;
894 }
895 if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
896 constructor = 1;
897 return 1;
898 }
899 if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
900 destructor = 1;
901 return 1;
902 }
903
904 return 0;
905}
906
907/*
908 * Called when a identifier has been declared, to give target last word.
909 */
910void
911fixdef(struct symtab *sp)
912{
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;
920 }
921}
922
923void
924pass1_lastchance(struct interpass *ip)
925{
926}
Note: See TracBrowser for help on using the repository browser.