1 /*      Id: local.c,v 1.33 2015/01/07 05:20:48 gmcgarry Exp     */
2 /*      $NetBSD: local.c,v 1.1.1.6 2016/02/09 20:28:11 plunky Exp $    */
3 /*
4  * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
5  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
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  * We define location operations which operate on the expression tree
31  * during the first pass (before sending to the backend for code generation.)
32  */
33 
34 #include <assert.h>
35 
36 #include "pass1.h"
37 
38 extern void defalign(int);
39 
40 /*
41  * clocal() is called to do local transformations on
42  * an expression tree before being sent to the backend.
43  */
44 NODE *
clocal(NODE * p)45 clocal(NODE *p)
46 {
47           struct symtab *q;
48           NODE *l, *r, *t;
49           int o;
50           int ty;
51           int tmpnr, isptrvoid = 0;
52           char *n;
53 
54           o = p->n_op;
55           switch (o) {
56 
57           case STASG:
58 
59                     l = p->n_left;
60                     r = p->n_right;
61                     if (r->n_op != STCALL && r->n_op != USTCALL)
62                               return p;
63 
64                     /* assign left node as first argument to function */
65                     nfree(p);
66                     t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap);
67                     l->n_rval = R0;
68                     l = buildtree(ADDROF, l, NIL);
69                     l = buildtree(ASSIGN, t, l);
70 
71                     if (r->n_right->n_op != CM) {
72                               r->n_right = block(CM, l, r->n_right, INT, 0, 0);
73                     } else {
74                               for (t = r->n_right; t->n_left->n_op == CM;
75                                   t = t->n_left)
76                                         ;
77                               t->n_left = block(CM, l, t->n_left, INT, 0, 0);
78                     }
79                     return r;
80 
81           case CALL:
82           case STCALL:
83           case USTCALL:
84                     if (p->n_type == VOID)
85                               break;
86                     /*
87                      * if the function returns void*, ecode() invokes
88                      * delvoid() to convert it to uchar*.
89                      * We just let this happen on the ASSIGN to the temp,
90                      * and cast the pointer back to void* on access
91                      * from the temp.
92                      */
93                     if (p->n_type == PTR+VOID)
94                               isptrvoid = 1;
95                     r = tempnode(0, p->n_type, p->n_df, p->n_ap);
96                     tmpnr = regno(r);
97                     r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
98 
99                     p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
100                     if (isptrvoid) {
101                               p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0);
102                     }
103                     p = buildtree(COMOP, r, p);
104                     break;
105 
106           case NAME:
107                     if ((q = p->n_sp) == NULL)
108                               return p;
109                     if (blevel == 0)
110                               return p;
111 
112                     switch (q->sclass) {
113                     case PARAM:
114                     case AUTO:
115                               /* fake up a structure reference */
116                               r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
117                               r->n_lval = 0;
118                               r->n_rval = FPREG;
119                               p = stref(block(STREF, r, p, 0, 0, 0));
120                               break;
121                     case REGISTER:
122                               p->n_op = REG;
123                               p->n_lval = 0;
124                               p->n_rval = q->soffset;
125                               break;
126                     case STATIC:
127                               if (q->slevel > 0) {
128                                         p->n_lval = 0;
129                                         p->n_sp = q;
130                               }
131                               /* FALL-THROUGH */
132                     default:
133                               ty = p->n_type;
134                               n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
135                               if (strncmp(n, "__builtin", 9) == 0)
136                                         break;
137                               p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_ap);
138                               p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap);
139                               break;
140                     }
141                     break;
142 
143           case STNAME:
144                     if ((q = p->n_sp) == NULL)
145                               return p;
146                     if (q->sclass != STNAME)
147                               return p;
148                     ty = p->n_type;
149                     p = block(ADDROF, p, NIL, INCREF(ty),
150                         p->n_df, p->n_ap);
151                     p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap);
152                     break;
153 
154           case FORCE:
155                     /* put return value in return reg */
156                     p->n_op = ASSIGN;
157                     p->n_right = p->n_left;
158                     p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
159                     p->n_left->n_rval = p->n_left->n_type == BOOL ?
160                         RETREG(BOOL_TYPE) : RETREG(p->n_type);
161                     break;
162 
163           case SCONV:
164                     l = p->n_left;
165                     if (p->n_type == l->n_type) {
166                               nfree(p);
167                               return l;
168                     }
169                     if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
170                         tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) {
171                               if (p->n_type != FLOAT && p->n_type != DOUBLE &&
172                                   l->n_type != FLOAT && l->n_type != DOUBLE &&
173                                   l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
174                                         if (l->n_op == NAME || l->n_op == UMUL ||
175                                             l->n_op == TEMP) {
176                                                   l->n_type = p->n_type;
177                                                   nfree(p);
178                                                   return l;
179                                         }
180                               }
181                     }
182 
183                     if (l->n_op == ICON) {
184                               CONSZ val = l->n_lval;
185 
186                               if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */
187                               switch (p->n_type) {
188                               case BOOL:
189                                         l->n_lval = l->n_lval != 0;
190                                         break;
191                               case CHAR:
192                                         l->n_lval = (char)val;
193                                         break;
194                               case UCHAR:
195                                         l->n_lval = val & 0377;
196                                         break;
197                               case SHORT:
198                                         l->n_lval = (short)val;
199                                         break;
200                               case USHORT:
201                                         l->n_lval = val & 0177777;
202                                         break;
203                               case ULONG:
204                               case UNSIGNED:
205                                         l->n_lval = val & 0xffffffff;
206                                         break;
207                               case LONG:
208                               case INT:
209                                         l->n_lval = (int)val;
210                                         break;
211                               case LONGLONG:
212                                         l->n_lval = (long long)val;
213                                         break;
214                               case ULONGLONG:
215                                         l->n_lval = val;
216                                         break;
217                               case VOID:
218                                         break;
219                               case LDOUBLE:
220                               case DOUBLE:
221                               case FLOAT:
222                                         l->n_op = FCON;
223                                         l->n_dcon = val;
224                                         break;
225                               default:
226                                         cerror("unknown type %d", l->n_type);
227                               }
228                               l->n_type = p->n_type;
229                               l->n_ap = 0;
230                               nfree(p);
231                               return l;
232                     } else if (p->n_op == FCON) {
233                               l->n_lval = l->n_dcon;
234                               l->n_sp = NULL;
235                               l->n_op = ICON;
236                               l->n_type = p->n_type;
237                               l->n_ap = 0;
238                               nfree(p);
239                               return clocal(l);
240                     }
241                     if ((DEUNSIGN(p->n_type) == CHAR ||
242                         DEUNSIGN(p->n_type) == SHORT) &&
243                         (l->n_type == FLOAT || l->n_type == DOUBLE ||
244                         l->n_type == LDOUBLE)) {
245                               p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
246                               p->n_left->n_type = INT;
247                               return p;
248                     }
249                     break;
250 
251           case PCONV:
252                     l = p->n_left;
253                     if (l->n_op == ICON) {
254                               l->n_lval = (unsigned)l->n_lval;
255                               goto delp;
256                     }
257                     if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
258                               p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
259                               break;
260                     }
261                     if (l->n_op == SCONV)
262                               break;
263                     if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
264                               goto delp;
265                     if (p->n_type > BTMASK && l->n_type > BTMASK)
266                               goto delp;
267                     break;
268 
269           delp:
270                     l->n_type = p->n_type;
271                     l->n_qual = p->n_qual;
272                     l->n_df = p->n_df;
273                     l->n_ap = p->n_ap;
274                     nfree(p);
275                     p = l;
276                     break;
277           }
278 
279           return p;
280 }
281 
282 /*
283  * Called before sending the tree to the backend.
284  */
285 void
myp2tree(NODE * p)286 myp2tree(NODE *p)
287 {
288           struct symtab *sp;
289 
290           if (p->n_op != FCON)
291                     return;
292 
293 #define IALLOC(sz)  (isinlining ? permalloc(sz) : tmpalloc(sz))
294 
295           sp = IALLOC(sizeof(struct symtab));
296           sp->sclass = STATIC;
297           sp->sap = 0;
298           sp->slevel = 1; /* fake numeric label */
299           sp->soffset = getlab();
300           sp->sflags = 0;
301           sp->stype = p->n_type;
302           sp->squal = (CON >> TSHIFT);
303 
304           defloc(sp);
305           ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
306 
307           p->n_op = NAME;
308           p->n_lval = 0;
309           p->n_sp = sp;
310 }
311 
312 /*
313  * Called during the first pass to determine if a NAME can be addressed.
314  *
315  * Return nonzero if supported, otherwise return 0.
316  */
317 int
andable(NODE * p)318 andable(NODE *p)
319 {
320           if (blevel == 0)
321                     return 1;
322           if (ISFTN(p->n_type))
323                     return 1;
324           return 0;
325 }
326 
327 /*
328  * Return 1 if a variable of type 't' is OK to put in register.
329  */
330 int
cisreg(TWORD t)331 cisreg(TWORD t)
332 {
333           if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
334                     return 0; /* not yet */
335           return 1;
336 }
337 
338 /*
339  * Allocate bits from the stack for dynamic-sized arrays.
340  *
341  * 'p' is the tree which represents the type being allocated.
342  * 'off' is the number of 'p's to be allocated.
343  * 't' is the storeable node where the address is written.
344  */
345 void
spalloc(NODE * t,NODE * p,OFFSZ off)346 spalloc(NODE *t, NODE *p, OFFSZ off)
347 {
348           NODE *sp;
349 
350           p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
351 
352           /* sub the size from sp */
353           sp = block(REG, NIL, NIL, p->n_type, 0, 0);
354           sp->n_lval = 0;
355           sp->n_rval = SP;
356           ecomp(buildtree(MINUSEQ, sp, p));
357 
358           /* save the address of sp */
359           sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
360           sp->n_lval = 0;
361           sp->n_rval = SP;
362           t->n_type = sp->n_type;
363           ecomp(buildtree(ASSIGN, t, sp));
364 }
365 
366 /*
367  * Print an integer constant node, may be associated with a label.
368  * Do not free the node after use.
369  * 'off' is bit offset from the beginning of the aggregate
370  * 'fsz' is the number of bits this is referring to
371  */
372 int
ninval(CONSZ off,int fsz,NODE * p)373 ninval(CONSZ off, int fsz, NODE *p)
374 {
375           union { float f; double d; int i[2]; } u;
376           struct symtab *q;
377           TWORD t;
378           int i, j;
379 
380           t = p->n_type;
381           if (t > BTMASK)
382                     t = p->n_type = INT; /* pointer */
383 
384           if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
385                     uerror("element not constant");
386 
387           switch (t) {
388           case LONGLONG:
389           case ULONGLONG:
390                     i = (p->n_lval >> 32);
391                     j = (p->n_lval & 0xffffffff);
392                     p->n_type = INT;
393                     if (features(FEATURE_BIGENDIAN)) {
394                               p->n_lval = i;
395                               ninval(off+32, 32, p);
396                               p->n_lval = j;
397                               ninval(off, 32, p);
398                     } else {
399                               p->n_lval = j;
400                               ninval(off, 32, p);
401                               p->n_lval = i;
402                               ninval(off+32, 32, p);
403                     }
404                     break;
405           case INT:
406           case UNSIGNED:
407                     printf("\t.word 0x%x", (int)p->n_lval);
408                     if ((q = p->n_sp) != NULL) {
409                               if ((q->sclass == STATIC && q->slevel > 0)) {
410                                         printf("+" LABFMT, q->soffset);
411                               } else
412                                         printf("+%s",
413                                             q->soname ? q->soname : exname(q->sname));
414                     }
415                     printf("\n");
416                     break;
417           case LDOUBLE:
418           case DOUBLE:
419                     u.d = (double)p->n_dcon;
420 #if defined(HOST_BIG_ENDIAN)
421                     if (features(FEATURE_BIGENDIAN))
422 #else
423                     if (!features(FEATURE_BIGENDIAN))
424 #endif
425                               printf("\t.word\t0x%x\n\t.word\t0x%x\n",
426                                   u.i[0], u.i[1]);
427                     else
428                               printf("\t.word\t0x%x\n\t.word\t0x%x\n",
429                                   u.i[1], u.i[0]);
430                     break;
431           case FLOAT:
432                     u.f = (float)p->n_dcon;
433                     printf("\t.word\t0x%x\n", u.i[0]);
434                     break;
435           default:
436                     return 0;
437           }
438           return 1;
439 }
440 
441 /*
442  * Prefix a leading underscore to a global variable (if necessary).
443  */
444 char *
exname(char * p)445 exname(char *p)
446 {
447           return (p == NULL ? "" : p);
448 }
449 
450 /*
451  * Map types which are not defined on the local machine.
452  */
453 TWORD
ctype(TWORD type)454 ctype(TWORD type)
455 {
456           switch (BTYPE(type)) {
457           case LONG:
458                     MODTYPE(type,INT);
459                     break;
460           case ULONG:
461                     MODTYPE(type,UNSIGNED);
462                     break;
463           }
464           return (type);
465 }
466 
467 /*
468  * Before calling a function do any tree re-writing for the local machine.
469  *
470  * 'p' is the function tree (NAME)
471  * 'q' is the CM-separated list of arguments.
472  */
473 void
calldec(NODE * p,NODE * q)474 calldec(NODE *p, NODE *q)
475 {
476 }
477 
478 /*
479  * While handling uninitialised variables, handle variables marked extern.
480  */
481 void
extdec(struct symtab * q)482 extdec(struct symtab *q)
483 {
484 }
485 
486 /* make a common declaration for id, if reasonable */
487 void
defzero(struct symtab * sp)488 defzero(struct symtab *sp)
489 {
490           int off;
491 
492           off = tsize(sp->stype, sp->sdf, sp->sap);
493           off = (off+(SZCHAR-1))/SZCHAR;
494           printf("  .%scomm ", sp->sclass == STATIC ? "l" : "");
495           if (sp->slevel == 0)
496                     printf("%s,0%o\n",
497                         sp->soname ? sp->soname : exname(sp->sname), off);
498           else
499                     printf(LABFMT ",0%o\n", sp->soffset, off);
500 }
501 
502 /*
503  * va_start(ap, last) implementation.
504  *
505  * f is the NAME node for this builtin function.
506  * a is the argument list containing:
507  *           CM
508  *        ap   last
509  */
510 NODE *
arm_builtin_stdarg_start(const struct bitable * bt,NODE * a)511 arm_builtin_stdarg_start(const struct bitable *bt, NODE *a)
512 {
513           NODE *p, *q;
514           int sz = 1;
515 
516           /* check num args and type */
517           if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
518               !ISPTR(a->n_left->n_type))
519                     goto bad;
520 
521           /* must first deal with argument size; use int size */
522           p = a->n_right;
523           if (p->n_type < INT) {
524                     /* round up to word */
525                     sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
526           }
527 
528           p = buildtree(ADDROF, p, NIL);  /* address of last arg */
529           p = optim(buildtree(PLUS, p, bcon(sz)));
530           q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
531           q = buildtree(CAST, q, p);
532           p = q->n_right;
533           nfree(q->n_left);
534           nfree(q);
535           p = buildtree(ASSIGN, a->n_left, p);
536           nfree(a);
537 
538           return p;
539 
540 bad:
541           uerror("bad argument to __builtin_stdarg_start");
542           return bcon(0);
543 }
544 
545 NODE *
arm_builtin_va_arg(const struct bitable * bt,NODE * a)546 arm_builtin_va_arg(const struct bitable *bt, NODE *a)
547 {
548           NODE *p, *q, *r;
549           int sz, tmpnr;
550 
551           /* check num args and type */
552           if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
553               !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
554                     goto bad;
555 
556           r = a->n_right;
557 
558           /* get type size */
559           sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
560           if (sz < SZINT/SZCHAR) {
561                     werror("%s%s promoted to int when passed through ...",
562                               ISUNSIGNED(r->n_type) ? "unsigned " : "",
563                               DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
564                     sz = SZINT/SZCHAR;
565           }
566 
567           /* alignment */
568           p = tcopy(a->n_left);
569           if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
570                     p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
571                     p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap);
572           }
573 
574           /* create a copy to a temp node */
575           q = tempnode(0, p->n_type, p->n_df, p->n_ap);
576           tmpnr = regno(q);
577           p = buildtree(ASSIGN, q, p);
578 
579           q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
580           q = buildtree(PLUS, q, bcon(sz));
581           q = buildtree(ASSIGN, a->n_left, q);
582 
583           q = buildtree(COMOP, p, q);
584 
585           nfree(a->n_right);
586           nfree(a);
587 
588           p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
589           p = buildtree(UMUL, p, NIL);
590           p = buildtree(COMOP, q, p);
591 
592           return p;
593 
594 bad:
595           uerror("bad argument to __builtin_va_arg");
596           return bcon(0);
597 }
598 
599 NODE *
arm_builtin_va_end(const struct bitable * bt,NODE * a)600 arm_builtin_va_end(const struct bitable *bt, NODE *a)
601 {
602           tfree(a);
603 
604           return bcon(0);
605 }
606 
607 NODE *
arm_builtin_va_copy(const struct bitable * bt,NODE * a)608 arm_builtin_va_copy(const struct bitable *bt, NODE *a)
609 {
610           NODE  *f;
611 
612           if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
613                     goto bad;
614           f = buildtree(ASSIGN, a->n_left, a->n_right);
615           nfree(a);
616           return f;
617 
618 bad:
619           uerror("bad argument to __buildtin_va_copy");
620           return bcon(0);
621 }
622 
623 char *nextsect;
624 static int constructor;
625 static int destructor;
626 
627 /*
628  * Give target the opportunity of handling pragmas.
629  */
630 int
mypragma(char * str)631 mypragma(char *str)
632 {
633           char *a2 = pragtok(NULL);
634 
635           if (strcmp(str, "tls") == 0) {
636                     uerror("thread-local storage not supported for this target");
637                     return 1;
638           }
639           if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
640                     constructor = 1;
641                     return 1;
642           }
643           if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
644                     destructor = 1;
645                     return 1;
646           }
647           if (strcmp(str, "section") == 0 && a2 != NULL) {
648                     nextsect = newstring(a2, strlen(a2));
649                     return 1;
650           }
651 
652           return 0;
653 }
654 
655 /*
656  * Called when a identifier has been declared, to give target last word.
657  */
658 void
fixdef(struct symtab * sp)659 fixdef(struct symtab *sp)
660 {
661           if ((constructor || destructor) && (sp->sclass != PARAM)) {
662                     printf("\t.section .%ctors,\"aw\",@progbits\n",
663                         constructor ? 'c' : 'd');
664                     printf("\t.p2align 2\n");
665                     printf("\t.long %s\n", exname(sp->sname));
666                     printf("\t.previous\n");
667                     constructor = destructor = 0;
668           }
669 }
670 
671 void
pass1_lastchance(struct interpass * ip)672 pass1_lastchance(struct interpass *ip)
673 {
674 }
675