1 /* Id: local.c,v 1.16 2016/01/30 17:26:19 ragge Exp */
2 /* $NetBSD: local.c,v 1.1.1.2 2016/02/09 20:28:34 plunky Exp $ */
3 /*
4 * Copyright (c) 2014 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 #include "pass1.h"
30
31 #undef NIL
32 #define NIL NULL
33
34 #ifdef LANG_CXX
35 #define P1ND NODE
36 #define p1nfree nfree
37 #define p1fwalk fwalk
38 #define p1tcopy tcopy
39 #define p1alloc talloc
40 #else
41 #define NODE P1ND
42 #define nfree p1nfree
43 #define fwalk p1fwalk
44 #endif
45
46
47 /* this file contains code which is dependent on the target machine */
48
49 int gotnr;
50
51 /*
52 * Make a symtab entry for PIC use.
53 */
54 static struct symtab *
picsymtab(char * p,char * s,char * s2)55 picsymtab(char *p, char *s, char *s2)
56 {
57 struct symtab *sp = permalloc(sizeof(struct symtab));
58 size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
59
60 sp->sname = permalloc(len);
61 strlcpy(sp->sname, p, len);
62 strlcat(sp->sname, s, len);
63 strlcat(sp->sname, s2, len);
64 sp->sap = attr_new(ATTR_SONAME, 1);
65 sp->sap->sarg(0) = sp->sname;
66 sp->sclass = EXTERN;
67 sp->sflags = sp->slevel = 0;
68 sp->stype = 0xdeadbeef;
69 return sp;
70 }
71
72 /*
73 * Create a reference for an extern variable.
74 */
75 static NODE *
picext(NODE * p)76 picext(NODE *p)
77 {
78 NODE *q, *r;
79 struct symtab *sp;
80 char *name;
81
82 q = tempnode(gotnr, PTR|VOID, 0, 0);
83 name = getexname(p->n_sp);
84
85 #ifdef notdef
86 struct attr *ga;
87 if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) &&
88 strcmp(ga->sarg(0), "hidden") == 0) {
89 /* For hidden vars use GOTOFF */
90 sp = picsymtab("", name, "@GOTOFF");
91 r = xbcon(0, sp, INT);
92 q = buildtree(PLUS, q, r);
93 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
94 q->n_sp = p->n_sp; /* for init */
95 nfree(p);
96 return q;
97 }
98 #endif
99
100 sp = picsymtab("", name, "@GOT");
101 r = xbcon(0, sp, INT);
102 q = buildtree(PLUS, q, r);
103 q = block(UMUL, q, 0, PTR|VOID, 0, 0);
104 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
105 q->n_sp = p->n_sp; /* for init */
106 nfree(p);
107 return q;
108 }
109
110 static char *
getsoname(struct symtab * sp)111 getsoname(struct symtab *sp)
112 {
113 struct attr *ap;
114 return (ap = attr_find(sp->sap, ATTR_SONAME)) ?
115 ap->sarg(0) : sp->sname;
116
117 }
118
119
120 static NODE *
picstatic(NODE * p)121 picstatic(NODE *p)
122 {
123 NODE *q, *r;
124 struct symtab *sp;
125
126 q = tempnode(gotnr, PTR|VOID, 0, 0);
127 if (p->n_sp->slevel > 0) {
128 char buf[32];
129 if ((p->n_sp->sflags & SMASK) == SSTRING)
130 p->n_sp->sflags |= SASG;
131 snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
132 sp = picsymtab("", buf, "@GOT");
133 } else {
134 sp = picsymtab("", getsoname(p->n_sp), "@GOT");
135 }
136
137 sp->sclass = STATIC;
138 sp->stype = p->n_sp->stype;
139 r = xbcon(0, sp, INT);
140 q = buildtree(PLUS, q, r);
141 q = block(UMUL, q, 0, PTR|VOID, 0, 0);
142 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
143 q->n_sp = p->n_sp; /* for init */
144 nfree(p);
145 return q;
146 }
147
148 /* clocal() is called to do local transformations on
149 * an expression tree preparitory to its being
150 * written out in intermediate code.
151 *
152 * the major essential job is rewriting the
153 * automatic variables and arguments in terms of
154 * REG and OREG nodes
155 * conversion ops which are not necessary are also clobbered here
156 * in addition, any special features (such as rewriting
157 * exclusive or) are easily handled here as well
158 */
159 NODE *
clocal(NODE * p)160 clocal(NODE *p)
161 {
162
163 register struct symtab *q;
164 register NODE *r, *l;
165 register int o;
166 TWORD t;
167
168 #ifdef PCC_DEBUG
169 if (xdebug) {
170 printf("clocal: %p\n", p);
171 fwalk(p, eprint, 0);
172 }
173 #endif
174 switch( o = p->n_op ){
175
176 case NAME:
177 if ((q = p->n_sp) == NULL)
178 return p; /* Nothing to care about */
179
180 switch (q->sclass) {
181
182 case PARAM:
183 case AUTO:
184 /* fake up a structure reference */
185 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
186 slval(r, 0);
187 r->n_rval = FPREG;
188 p = stref(block(STREF, r, p, 0, 0, 0));
189 break;
190
191 case REGISTER:
192 p->n_op = REG;
193 slval(p, 0);
194 p->n_rval = q->soffset;
195 break;
196
197 case USTATIC:
198 case STATIC:
199 if (kflag == 0)
200 break;
201 if (blevel > 0 && !statinit)
202 p = picstatic(p);
203 break;
204
205 case EXTERN:
206 case EXTDEF:
207 if (kflag == 0)
208 break;
209 if (blevel > 0 && !statinit)
210 p = picext(p);
211 break;
212 }
213 break;
214
215 case ADDROF:
216 if (kflag == 0 || blevel == 0 || statinit)
217 break;
218 /* char arrays may end up here */
219 l = p->n_left;
220 if (l->n_op != NAME ||
221 (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
222 break;
223 l = p;
224 p = picstatic(p->n_left);
225 nfree(l);
226 if (p->n_op != UMUL)
227 cerror("ADDROF error");
228 l = p;
229 p = p->n_left;
230 nfree(l);
231 break;
232
233 case STASG: /* convert struct assignment to call memcpy */
234 l = p->n_left;
235 if (l->n_op == NAME && ISFTN(l->n_sp->stype))
236 break; /* struct return, do nothing */
237 /* first construct arg list */
238 p->n_left = buildtree(ADDROF, p->n_left, 0);
239 r = bcon(tsize(STRTY, p->n_df, p->n_ap)/SZCHAR);
240 p->n_left = buildtree(CM, p->n_left, p->n_right);
241 p->n_right = r;
242 p->n_op = CM;
243 p->n_type = INT;
244
245 r = block(NAME, NIL, NIL, INT, 0, 0);
246 r->n_sp = lookup(addname("memcpy"), SNORMAL);
247 if (r->n_sp->sclass == SNULL) {
248 r->n_sp->sclass = EXTERN;
249 r->n_sp->stype = INCREF(VOID+PTR)+(FTN-PTR);
250 }
251 r->n_type = r->n_sp->stype;
252 p = buildtree(CALL, r, p);
253 break;
254
255 case SCONV:
256 l = p->n_left;
257 if (l->n_op == ICON && ISPTR(l->n_type)) {
258 /* Do immediate cast here */
259 /* Should be common code */
260 q = l->n_sp;
261 l->n_sp = NULL;
262 l->n_type = UNSIGNED;
263 if (concast(l, p->n_type) == 0)
264 cerror("clocal");
265 p = nfree(p);
266 p->n_sp = q;
267 }
268 break;
269
270 case FORCE:
271 /* put return value in return reg */
272 p->n_op = ASSIGN;
273 p->n_right = p->n_left;
274 p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
275 t = p->n_type;
276 if (ISITY(t))
277 t = t - (FIMAG-FLOAT);
278 p->n_left->n_rval = RETREG(t);
279 break;
280 }
281 #ifdef PCC_DEBUG
282 if (xdebug) {
283 printf("clocal end: %p\n", p);
284 fwalk(p, eprint, 0);
285 }
286 #endif
287 return(p);
288 }
289
290 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
291
292 void
myp2tree(NODE * p)293 myp2tree(NODE *p)
294 {
295 struct symtab *sp;
296 NODE *l;
297
298 if (cdope(p->n_op) & CALLFLG) {
299 if (p->n_left->n_op == ADDROF &&
300 p->n_left->n_left->n_op == NAME) {
301 p->n_left = nfree(p->n_left);
302 l = p->n_left;
303 l->n_op = ICON;
304 if (l->n_sp->sclass != STATIC &&
305 l->n_sp->sclass != USTATIC)
306 l->n_sp =
307 picsymtab(l->n_sp->sname, "@PLTPC", "");
308 }
309 }
310
311 if (p->n_op != FCON)
312 return;
313
314 sp = IALLOC(sizeof(struct symtab));
315 sp->sclass = STATIC;
316 sp->sap = 0;
317 sp->slevel = 1; /* fake numeric label */
318 sp->soffset = getlab();
319 sp->sflags = 0;
320 sp->stype = p->n_type;
321 sp->squal = (CON >> TSHIFT);
322 sp->sname = NULL;
323
324 locctr(DATA, sp);
325 defloc(sp);
326 ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
327
328 p->n_op = NAME;
329 slval(p, 0);
330 p->n_sp = sp;
331
332 }
333
334 /*
335 * Convert ADDROF NAME to ICON?
336 */
337 int
andable(NODE * p)338 andable(NODE *p)
339 {
340 #ifdef notdef
341 /* shared libraries cannot have direct referenced static syms */
342 if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC)
343 return 1;
344 #endif
345 return 1;
346 }
347
348 /*
349 * Return 1 if a variable of type type is OK to put in register.
350 */
351 int
cisreg(TWORD t)352 cisreg(TWORD t)
353 {
354 return 1;
355 }
356
357 /*
358 * Allocate off bits on the stack. p is a tree that when evaluated
359 * is the multiply count for off, t is a storeable node where to write
360 * the allocated address.
361 */
362 void
spalloc(NODE * t,NODE * p,OFFSZ off)363 spalloc(NODE *t, NODE *p, OFFSZ off)
364 {
365 NODE *sp;
366
367 p = buildtree(MUL, p, bcon(off/SZCHAR));
368 p = buildtree(PLUS, p, bcon(30));
369 p = buildtree(AND, p, xbcon(-16, NULL, UNSIGNED));
370 p = cast(p, UNSIGNED, 0);
371
372 /* sub the size from sp */
373 sp = block(REG, NIL, NIL, UNSIGNED+PTR, 0, 0);
374 slval(sp, 0);
375 sp->n_rval = STKREG;
376 p = (buildtree(MINUSEQ, sp, p));
377 ecomp(p);
378
379 /* save the address of sp */
380 sp = block(REG, NIL, NIL, PTR+UNSIGNED, t->n_df, t->n_ap);
381 slval(sp, 0);
382 sp->n_rval = STKREG;
383 t->n_type = sp->n_type;
384 p = (buildtree(ASSIGN, t, sp)); /* Emit! */
385 ecomp(p);
386
387 }
388
389 /*
390 * print out a constant node, may be associated with a label.
391 * Do not free the node after use.
392 * off is bit offset from the beginning of the aggregate
393 * fsz is the number of bits this is referring to
394 */
395 int
ninval(CONSZ off,int fsz,NODE * p)396 ninval(CONSZ off, int fsz, NODE *p)
397 {
398 union { float f; double d; long double l; int i[3]; } u;
399
400 switch (p->n_type) {
401 case LDOUBLE:
402 u.i[2] = 0;
403 u.l = (long double)((union flt *)p->n_dcon)->fp;
404 #if defined(HOST_LITTLE_ENDIAN)
405 /* XXX probably broken on most hosts */
406 printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
407 #else
408 printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
409 #endif
410 break;
411 case DOUBLE:
412 u.d = (double)((union flt *)p->n_dcon)->fp;
413 #if defined(HOST_LITTLE_ENDIAN)
414 printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
415 #else
416 printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
417 #endif
418 break;
419 case FLOAT:
420 u.f = (float)((union flt *)p->n_dcon)->fp;
421 printf("\t.long\t0x%x\n", u.i[0]);
422 break;
423
424 case LONGLONG:
425 case ULONGLONG:
426 printf("\t.long\t0x%x\n", (int)(off >> 32) & 0xffffffff);
427 printf("\t.long\t0x%x\n", (int)(off) & 0xffffffff);
428 break;
429 default:
430 return 0;
431 }
432 return 1;
433 }
434
435 /* make a name look like an external name in the local machine */
436 char *
exname(char * p)437 exname(char *p)
438 {
439 return (p == NULL ? "" : p);
440 }
441
442 /*
443 * map types which are not defined on the local machine
444 */
445 TWORD
ctype(TWORD type)446 ctype(TWORD type)
447 {
448 switch (BTYPE(type)) {
449 case LONG:
450 MODTYPE(type,INT);
451 break;
452
453 case ULONG:
454 MODTYPE(type,UNSIGNED);
455
456 }
457 return (type);
458 }
459
460 void
calldec(NODE * p,NODE * q)461 calldec(NODE *p, NODE *q)
462 {
463 }
464
465 void
extdec(struct symtab * q)466 extdec(struct symtab *q)
467 {
468 }
469
470 /* make a common declaration for id, if reasonable */
471 void
defzero(struct symtab * sp)472 defzero(struct symtab *sp)
473 {
474 int off, al;
475 char *name;
476
477 name = getexname(sp);
478 off = tsize(sp->stype, sp->sdf, sp->sap);
479 SETOFF(off,SZCHAR);
480 off /= SZCHAR;
481 al = talign(sp->stype, sp->sap)/SZCHAR;
482
483 if (sp->sclass == STATIC) {
484 if (sp->slevel == 0) {
485 printf("\t.local %s\n", name);
486 } else
487 printf("\t.local " LABFMT "\n", sp->soffset);
488 }
489 if (sp->slevel == 0) {
490 printf("\t.comm %s,0%o,%d\n", name, off, al);
491 } else
492 printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al);
493 }
494
495 char *nextsect;
496 static char *alias;
497 static int constructor;
498 static int destructor;
499
500 /*
501 * Give target the opportunity of handling pragmas.
502 */
503 int
mypragma(char * str)504 mypragma(char *str)
505 {
506 return 0;
507 }
508
509 /*
510 * Called when a identifier has been declared.
511 */
512 void
fixdef(struct symtab * sp)513 fixdef(struct symtab *sp)
514 {
515 struct attr *ga;
516
517 #ifdef HAVE_WEAKREF
518 /* not many as'es have this directive */
519 if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
520 char *wr = ga->sarg(0);
521 char *sn = getsoname(sp);
522 if (wr == NULL) {
523 if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) {
524 wr = ga->sarg(0);
525 }
526 }
527 if (wr == NULL)
528 printf("\t.weak %s\n", sn);
529 else
530 printf("\t.weakref %s,%s\n", sn, wr);
531 } else
532 if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
533 char *an = ga->sarg(0);
534 char *sn = getsoname(sp);
535 char *v;
536
537 v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
538 printf("\t.%s %s\n", v, sn);
539 printf("\t.set %s,%s\n", sn, an);
540 }
541 if (alias != NULL && (sp->sclass != PARAM)) {
542 char *name = getexname(sp);
543 printf("\t.globl %s\n", name);
544 printf("%s = ", name);
545 printf("%s\n", exname(alias));
546 alias = NULL;
547 }
548 if ((constructor || destructor) && (sp->sclass != PARAM)) {
549 NODE *p = p1alloc();
550
551 p->n_op = NAME;
552 p->n_sp =
553 (struct symtab *)(constructor ? "constructor" : "destructor");
554 sp->sap = attr_add(sp->sap, gcc_attr_parse(p));
555 constructor = destructor = 0;
556 }
557 #endif
558 }
559
560 void
pass1_lastchance(struct interpass * ip)561 pass1_lastchance(struct interpass *ip)
562 {
563 }
564