1 /* Id: local.c,v 1.34 2012/09/06 13:07:29 plunky Exp */
2 /* $NetBSD: local.c,v 1.1.1.5 2014/07/24 19:20:27 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 #include <assert.h>
29 #include "pass1.h"
30
31 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
32
33 extern int kflag;
34
35 static void simmod(NODE *p);
36
37 /* this file contains code which is dependent on the target machine */
38
39 #if defined(MACHOABI)
40
41 /*
42 * Keep track of PIC stubs.
43 */
44
45 void
addstub(struct stub * list,char * name)46 addstub(struct stub *list, char *name)
47 {
48 struct stub *s;
49
50 DLIST_FOREACH(s, list, link) {
51 if (strcmp(s->name, name) == 0)
52 return;
53 }
54
55 s = permalloc(sizeof(struct stub));
56 s->name = newstring(name, strlen(name));
57 DLIST_INSERT_BEFORE(list, s, link);
58 }
59
60 #endif
61
62
63 /*
64 * Make a symtab entry for PIC use.
65 */
66 static struct symtab *
picsymtab(char * p,char * s,char * s2)67 picsymtab(char *p, char *s, char *s2)
68 {
69 struct symtab *sp = IALLOC(sizeof(struct symtab));
70 size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
71
72 sp->sname = sp->soname = IALLOC(len);
73 strlcpy(sp->soname, p, len);
74 strlcat(sp->soname, s, len);
75 strlcat(sp->soname, s2, len);
76 sp->sclass = EXTERN;
77 sp->sflags = sp->slevel = 0;
78
79 return sp;
80 }
81
82 int gotnr; /* tempnum for GOT register */
83
84 /*
85 * Create a reference for an extern variable.
86 */
87 static NODE *
picext(NODE * p)88 picext(NODE *p)
89 {
90 NODE *q;
91 struct symtab *sp;
92 char *name;
93
94 name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
95
96 if (strncmp(name, "__builtin", 9) == 0)
97 return p;
98
99 #if defined(ELFABI)
100
101 sp = picsymtab("", name, "@got(31)");
102 q = xbcon(0, sp, PTR+VOID);
103 q = block(UMUL, q, 0, PTR+VOID, 0, 0);
104
105 #elif defined(MACHOABI)
106
107 char buf2[64];
108 NODE *r;
109 char *fname;
110
111 fname = cftnsp->soname ? cftnsp->soname : cftnsp->sname;
112
113 if (p->n_sp->sclass == EXTDEF) {
114 snprintf(buf2, 64, "-L%s$pb", fname);
115 sp = picsymtab("", name, buf2);
116 } else {
117 snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", fname);
118 sp = picsymtab("L", name, buf2);
119 addstub(&nlplist, name);
120 }
121 #if USE_GOTNR
122 q = tempnode(gotnr, PTR+VOID, 0, 0);
123 #else
124 q = block(REG, NIL, NIL, PTR+VOID, 0, 0);
125 regno(q) = GOTREG;
126 #endif
127 r = xbcon(0, sp, INT);
128 q = buildtree(PLUS, q, r);
129
130 if (p->n_sp->sclass != EXTDEF)
131 q = block(UMUL, q, 0, PTR+VOID, 0, 0);
132
133 #endif
134
135 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
136 q->n_sp = p->n_sp; /* for init */
137 nfree(p);
138
139 return q;
140 }
141
142 /*
143 * Create a reference for a static variable
144 */
145
146 static NODE *
picstatic(NODE * p)147 picstatic(NODE *p)
148 {
149 NODE *q;
150 struct symtab *sp;
151
152 #if defined(ELFABI)
153 char *n;
154
155 if (p->n_sp->slevel > 0) {
156 char buf[64];
157 snprintf(buf, 64, LABFMT, (int)p->n_sp->soffset);
158 sp = picsymtab("", buf, "@got(31)");
159 } else {
160 n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
161 sp = picsymtab("", exname(n), "@got(31)");
162 }
163 sp->sclass = STATIC;
164 sp->stype = p->n_sp->stype;
165 q = xbcon(0, sp, PTR+VOID);
166 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
167 q->n_sp = p->n_sp;
168 nfree(p);
169
170 #elif defined(MACHOABI)
171
172 char buf2[64];
173 NODE *r;
174
175 snprintf(buf2, 64, "-L%s$pb",
176 cftnsp->soname ? cftnsp->soname : cftnsp->sname);
177
178 if (p->n_sp->slevel > 0) {
179 char buf1[64];
180 snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset);
181 sp = picsymtab("", buf1, buf2);
182 } else {
183 char *name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
184 sp = picsymtab("", name, buf2);
185 }
186 sp->sclass = STATIC;
187 sp->stype = p->n_sp->stype;
188 #if USE_GOTNR
189 q = tempnode(gotnr, PTR+VOID, 0, 0);
190 #else
191 q = block(REG, NIL, NIL, PTR+VOID, 0, 0);
192 regno(q) = GOTREG;
193 #endif
194 r = xbcon(0, sp, INT);
195 q = buildtree(PLUS, q, r);
196 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
197 q->n_sp = p->n_sp;
198 nfree(p);
199
200 #endif
201
202 return q;
203 }
204
205 static NODE *
convert_ulltof(NODE * p)206 convert_ulltof(NODE *p)
207 {
208 NODE *q, *r, *l, *t;
209 int ty;
210 int tmpnr;
211
212 ty = p->n_type;
213 l = p->n_left;
214 nfree(p);
215
216 q = tempnode(0, ULONGLONG, 0, 0);
217 tmpnr = regno(q);
218 t = buildtree(ASSIGN, q, l);
219 ecomp(t);
220
221 #if 0
222 q = tempnode(tmpnr, ULONGLONG, 0, 0);
223 q = block(SCONV, q, NIL, LONGLONG, 0, 0);
224 #endif
225 q = tempnode(tmpnr, LONGLONG, 0, 0);
226 r = block(SCONV, q, NIL, ty, 0, 0);
227
228 q = tempnode(tmpnr, ULONGLONG, 0, 0);
229 q = block(RS, q, bcon(1), ULONGLONG, 0, 0);
230 q = block(SCONV, q, NIL, LONGLONG, 0, 0);
231 q = block(SCONV, q, NIL, ty, 0, 0);
232 t = block(FCON, NIL, NIL, ty, 0, 0);
233 t->n_dcon = 2;
234 l = block(MUL, q, t, ty, 0, 0);
235
236 r = buildtree(COLON, l, r);
237
238 q = tempnode(tmpnr, ULONGLONG, 0, 0);
239 q = block(SCONV, q, NIL, LONGLONG, 0, 0);
240 l = block(LE, q, xbcon(0, NULL, LONGLONG), INT, 0, 0);
241
242 return clocal(buildtree(QUEST, l, r));
243
244 }
245
246
247 /* clocal() is called to do local transformations on
248 * an expression tree preparitory to its being
249 * written out in intermediate code.
250 *
251 * the major essential job is rewriting the
252 * automatic variables and arguments in terms of
253 * REG and OREG nodes
254 * conversion ops which are not necessary are also clobbered here
255 * in addition, any special features (such as rewriting
256 * exclusive or) are easily handled here as well
257 */
258 NODE *
clocal(NODE * p)259 clocal(NODE *p)
260 {
261
262 struct symtab *q;
263 NODE *r, *l;
264 int o;
265 int m;
266 TWORD t;
267 int isptrvoid = 0;
268 int tmpnr;
269
270 #ifdef PCC_DEBUG
271 if (xdebug) {
272 printf("clocal: %p\n", p);
273 fwalk(p, eprint, 0);
274 }
275 #endif
276 switch (o = p->n_op) {
277
278 case ADDROF:
279 #ifdef PCC_DEBUG
280 if (xdebug) {
281 printf("clocal(): ADDROF\n");
282 printf("type: 0x%x\n", p->n_type);
283 }
284 #endif
285 /* XXX cannot takes addresses of PARAMs */
286
287 if (kflag == 0 || blevel == 0)
288 break;
289 /* char arrays may end up here */
290 l = p->n_left;
291 if (l->n_op != NAME ||
292 (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
293 break;
294 l = p;
295 p = picstatic(p->n_left);
296 nfree(l);
297 if (p->n_op != UMUL)
298 cerror("ADDROF error");
299 l = p;
300 p = p->n_left;
301 nfree(l);
302 break;
303
304 case NAME:
305 if ((q = p->n_sp) == NULL)
306 return p; /* Nothing to care about */
307
308 switch (q->sclass) {
309
310 case PARAM:
311 case AUTO:
312 /* fake up a structure reference */
313 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
314 r->n_lval = 0;
315 r->n_rval = FPREG;
316 p = stref(block(STREF, r, p, 0, 0, 0));
317 break;
318
319 case USTATIC:
320 if (kflag == 0)
321 break;
322 /* FALLTHROUGH */
323
324 case STATIC:
325 if (kflag == 0) {
326 if (q->slevel == 0)
327 break;
328 p->n_lval = 0;
329 } else if (blevel > 0) {
330 p = picstatic(p);
331 }
332 break;
333
334 case REGISTER:
335 p->n_op = REG;
336 p->n_lval = 0;
337 p->n_rval = q->soffset;
338 break;
339
340 case EXTERN:
341 case EXTDEF:
342 if (kflag == 0)
343 break;
344 if (blevel > 0)
345 p = picext(p);
346 break;
347 }
348 break;
349
350 case UCALL:
351 case CALL:
352 case USTCALL:
353 case STCALL:
354 if (p->n_type == VOID)
355 break;
356 /*
357 * if the function returns void*, ecode() invokes
358 * delvoid() to convert it to uchar*.
359 * We just let this happen on the ASSIGN to the temp,
360 * and cast the pointer back to void* on access
361 * from the temp.
362 */
363 if (p->n_type == PTR+VOID)
364 isptrvoid = 1;
365 r = tempnode(0, p->n_type, p->n_df, p->n_ap);
366 tmpnr = regno(r);
367 r = buildtree(ASSIGN, r, p);
368
369 p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
370 if (isptrvoid) {
371 p = block(PCONV, p, NIL, PTR+VOID,
372 p->n_df, 0);
373 }
374 #if 1
375 p = buildtree(COMOP, r, p);
376 #else
377 /* XXX this doesn't work if the call is already in a COMOP */
378 r = clocal(r);
379 ecomp(r);
380 #endif
381 break;
382
383 case CBRANCH:
384 l = p->n_left;
385
386 /*
387 * Remove unnecessary conversion ops.
388 */
389 if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
390 if (coptype(l->n_op) != BITYPE)
391 break;
392 if (l->n_right->n_op == ICON) {
393 r = l->n_left->n_left;
394 if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
395 break;
396 /* Type must be correct */
397 t = r->n_type;
398 nfree(l->n_left);
399 l->n_left = r;
400 l->n_type = t;
401 l->n_right->n_type = t;
402 }
403 }
404 break;
405
406 case PCONV:
407 /* Remove redundant PCONV's. Be careful */
408 l = p->n_left;
409 if (l->n_op == ICON) {
410 l->n_lval = (unsigned)l->n_lval;
411 goto delp;
412 }
413 if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
414 /* float etc? */
415 p->n_left = block(SCONV, l, NIL,
416 UNSIGNED, 0, 0);
417 break;
418 }
419 /* if left is SCONV, cannot remove */
420 if (l->n_op == SCONV)
421 break;
422
423 /* avoid ADDROF TEMP */
424 if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
425 break;
426
427 /* if conversion to another pointer type, just remove */
428 if (p->n_type > BTMASK && l->n_type > BTMASK)
429 goto delp;
430 break;
431
432 delp: l->n_type = p->n_type;
433 l->n_qual = p->n_qual;
434 l->n_df = p->n_df;
435 l->n_ap = p->n_ap;
436 nfree(p);
437 p = l;
438 break;
439
440 case SCONV:
441 l = p->n_left;
442
443 if (p->n_type == l->n_type) {
444 nfree(p);
445 return l;
446 }
447
448 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
449 tsize(p->n_type, p->n_df, p->n_ap) ==
450 tsize(l->n_type, l->n_df, l->n_ap)) {
451 if (p->n_type != FLOAT && p->n_type != DOUBLE &&
452 l->n_type != FLOAT && l->n_type != DOUBLE &&
453 l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
454 if (l->n_op == NAME || l->n_op == UMUL ||
455 l->n_op == TEMP) {
456 l->n_type = p->n_type;
457 nfree(p);
458 return l;
459 }
460 }
461 }
462
463 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
464 coptype(l->n_op) == BITYPE) {
465 l->n_type = p->n_type;
466 nfree(p);
467 return l;
468 }
469
470 /*
471 * if converting ULONGLONG to FLOAT/(L)DOUBLE,
472 * replace ___floatunsdidf() with ___floatdidf()
473 */
474 if (l->n_type == ULONGLONG && p->n_type >= FLOAT &&
475 p->n_type <= LDOUBLE) {
476 return convert_ulltof(p);
477 }
478
479 o = l->n_op;
480 m = p->n_type;
481
482 if (o == ICON) {
483 CONSZ val = l->n_lval;
484
485 if (!ISPTR(m)) /* Pointers don't need to be conv'd */
486 switch (m) {
487 case BOOL:
488 l->n_lval = l->n_lval != 0;
489 break;
490 case CHAR:
491 l->n_lval = (char)val;
492 break;
493 case UCHAR:
494 l->n_lval = val & 0377;
495 break;
496 case SHORT:
497 l->n_lval = (short)val;
498 break;
499 case USHORT:
500 l->n_lval = val & 0177777;
501 break;
502 case ULONG:
503 case UNSIGNED:
504 l->n_lval = val & 0xffffffff;
505 break;
506 case LONG:
507 case INT:
508 l->n_lval = (int)val;
509 break;
510 case LONGLONG:
511 l->n_lval = (long long)val;
512 break;
513 case ULONGLONG:
514 l->n_lval = val;
515 break;
516 case VOID:
517 break;
518 case LDOUBLE:
519 case DOUBLE:
520 case FLOAT:
521 l->n_op = FCON;
522 l->n_dcon = val;
523 break;
524 default:
525 cerror("unknown type %d", m);
526 }
527 l->n_type = m;
528 l->n_ap = 0;
529 nfree(p);
530 return l;
531 } else if (o == FCON) {
532 l->n_lval = l->n_dcon;
533 l->n_sp = NULL;
534 l->n_op = ICON;
535 l->n_type = m;
536 l->n_ap = 0;
537 nfree(p);
538 return clocal(l);
539 }
540 if (DEUNSIGN(p->n_type) == SHORT &&
541 DEUNSIGN(l->n_type) == SHORT) {
542 nfree(p);
543 p = l;
544 }
545 if ((DEUNSIGN(p->n_type) == CHAR ||
546 DEUNSIGN(p->n_type) == SHORT) &&
547 (l->n_type == FLOAT || l->n_type == DOUBLE ||
548 l->n_type == LDOUBLE)) {
549 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
550 p->n_left->n_type = INT;
551 return p;
552 }
553 if ((DEUNSIGN(l->n_type) == CHAR ||
554 DEUNSIGN(l->n_type) == SHORT) &&
555 (p->n_type == FLOAT || p->n_type == DOUBLE ||
556 p->n_type == LDOUBLE)) {
557 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
558 p->n_left->n_type = INT;
559 return p;
560 }
561 break;
562
563 case MOD:
564 simmod(p);
565 break;
566
567 case DIV:
568 if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
569 break;
570 /* make it an int division by inserting conversions */
571 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
572 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
573 p = block(SCONV, p, NIL, p->n_type, 0, 0);
574 p->n_left->n_type = INT;
575 break;
576
577 case STNAME:
578 if ((q = p->n_sp) == NULL)
579 return p;
580 if (q->sclass != STNAME)
581 return p;
582 t = p->n_type;
583 p = block(ADDROF, p, NIL, INCREF(t), p->n_df, p->n_ap);
584 p = block(UMUL, p, NIL, t, p->n_df, p->n_ap);
585 break;
586
587 case FORCE:
588 /* put return value in return reg */
589 p->n_op = ASSIGN;
590 p->n_right = p->n_left;
591 p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
592 p->n_left->n_rval = p->n_left->n_type == BOOL ?
593 RETREG(BOOL_TYPE) : RETREG(p->n_type);
594 break;
595
596 case LS:
597 case RS:
598 if (p->n_right->n_op == ICON)
599 break; /* do not do anything */
600 if (DEUNSIGN(p->n_right->n_type) == INT)
601 break;
602 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
603 break;
604 }
605
606 #ifdef PCC_DEBUG
607 if (xdebug) {
608 printf("clocal end: %p\n", p);
609 fwalk(p, eprint, 0);
610 }
611 #endif
612 return(p);
613 }
614
615 /*
616 * Change CALL references to either direct (static) or PLT.
617 */
618 static void
fixnames(NODE * p,void * arg)619 fixnames(NODE *p, void *arg)
620 {
621 struct symtab *sp;
622 struct attr *ap;
623 NODE *q;
624 char *c;
625 int isu;
626
627 if ((cdope(p->n_op) & CALLFLG) == 0)
628 return;
629
630 isu = 0;
631 q = p->n_left;
632 ap = q->n_ap;
633 if (q->n_op == UMUL)
634 q = q->n_left, isu = 1;
635
636 #if defined(ELFABI)
637
638 if (q->n_op == ICON) {
639 sp = q->n_sp;
640
641 #elif defined(MACHOABI)
642
643 #ifdef USE_GOTNR
644 if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
645 #else
646 if (q->n_op == PLUS && q->n_left->n_op == REG &&
647 #endif
648 q->n_right->n_op == ICON) {
649 sp = q->n_right->n_sp;
650 #endif
651
652 if (sp == NULL)
653 return; /* nothing to do */
654 if (sp->sclass == STATIC && !ISFTN(sp->stype))
655 return; /* function pointer */
656
657 if (sp->sclass != STATIC && sp->sclass != EXTERN &&
658 sp->sclass != EXTDEF)
659 cerror("fixnames");
660 c = NULL;
661 #if defined(ELFABI)
662
663 if (sp->soname == NULL ||
664 (c = strstr(sp->soname, "@got(31)")) == NULL)
665 cerror("fixnames2");
666 if (isu) {
667 memcpy(c, "@plt", sizeof("@plt"));
668 } else
669 *c = 0;
670
671 #elif defined(MACHOABI)
672
673 if (sp->soname == NULL ||
674 ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL &&
675 (c = strstr(sp->soname, "-L")) == NULL))
676 cerror("fixnames2");
677 if (isu) {
678 addstub(&stublist, sp->soname+1);
679 memcpy(c, "$stub", sizeof("$stub"));
680 } else
681 *c = 0;
682
683 nfree(q->n_left);
684 q = q->n_right;
685 if (isu)
686 nfree(p->n_left->n_left);
687 nfree(p->n_left);
688 p->n_left = q;
689 q->n_ap = ap;
690
691 #endif
692 }
693 }
694
695 void
696 myp2tree(NODE *p)
697 {
698 int o = p->n_op;
699 struct symtab *sp;
700
701 if (kflag)
702 walkf(p, fixnames, 0);
703 if (o != FCON)
704 return;
705
706 /* Write float constants to memory */
707 /* Should be voluntary per architecture */
708
709 sp = IALLOC(sizeof(struct symtab));
710 sp->sclass = STATIC;
711 sp->sap = 0;
712 sp->slevel = 1; /* fake numeric label */
713 sp->soffset = getlab();
714 sp->sflags = 0;
715 sp->stype = p->n_type;
716 sp->squal = (CON >> TSHIFT);
717
718 defloc(sp);
719 ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
720
721 p->n_op = NAME;
722 p->n_lval = 0;
723 p->n_sp = sp;
724 }
725
726 /*ARGSUSED*/
727 int
728 andable(NODE *p)
729 {
730 return(1); /* all names can have & taken on them */
731 }
732
733 /*
734 * Return 1 if a variable of type type is OK to put in register.
735 */
736 int
737 cisreg(TWORD t)
738 {
739 return 1;
740 }
741
742 /*
743 * Allocate bits on the stack.
744 * 'off' is the number of bits to allocate
745 * 'p' is a tree that when evaluated is the multiply count for 'off'
746 * 't' is a storeable node where to write the allocated address
747 */
748 void
749 spalloc(NODE *t, NODE *p, OFFSZ off)
750 {
751 NODE *q, *r;
752 int nbytes = off / SZCHAR;
753 int stacksize = 24+40; /* this should be p2stacksize */
754
755 /*
756 * After we subtract the requisite bytes
757 * off the stack, we need to step back over
758 * the 40 bytes for the arguments registers
759 * *and* any other parameters which will get
760 * saved to the stack. Unfortunately, we
761 * don't have that information in pass1 and
762 * the parameters will stomp on the allocated
763 * space for alloca().
764 *
765 * No fix yet.
766 */
767 werror("parameters may stomp on alloca()");
768
769 /* compute size */
770 p = buildtree(MUL, p, bcon(nbytes));
771 p = buildtree(PLUS, p, bcon(ALSTACK/SZCHAR));
772
773 /* load the top-of-stack */
774 q = block(REG, NIL, NIL, PTR+INT, 0, 0);
775 regno(q) = SPREG;
776 q = block(UMUL, q, NIL, INT, 0, 0);
777
778 /* save old top-of-stack value to new top-of-stack position */
779 r = block(REG, NIL, NIL, PTR+INT, 0, 0);
780 regno(r) = SPREG;
781 r = block(MINUSEQ, r, p, INT, 0, 0);
782 r = block(UMUL, r, NIL, INT, 0, 0);
783 ecomp(buildtree(ASSIGN, r, q));
784
785 r = block(REG, NIL, NIL, PTR+INT, 0, 0);
786 regno(r) = SPREG;
787
788 /* skip over the arguments space and align to 16 bytes */
789 r = block(PLUS, r, bcon(stacksize + 15), INT, 0, 0);
790 r = block(RS, r, bcon(4), INT, 0, 0);
791 r = block(LS, r, bcon(4), INT, 0, 0);
792
793 t->n_type = p->n_type;
794 ecomp(buildtree(ASSIGN, t, r));
795 }
796
797 /*
798 * Print out a string of characters.
799 * Unfortunately, this code assumes that the assembler understands
800 * C-style escape sequences. (which it doesn't!)
801 * Location is already set.
802 */
803 void
804 instring(struct symtab *sp)
805 {
806 char *s, *str = sp->sname;
807
808 #if defined(ELFABI)
809
810 defloc(sp);
811
812 #elif defined(MACHOABI)
813
814 extern int lastloc;
815 if (lastloc != STRNG)
816 printf(" .cstring\n");
817 lastloc = STRNG;
818 printf("\t.p2align 2\n");
819 printf(LABFMT ":\n", sp->soffset);
820
821 #endif
822
823 /* be kind to assemblers and avoid long strings */
824 printf("\t.ascii \"");
825 for (s = str; *s != 0; ) {
826 if (*s++ == '\\') {
827 (void)esccon(&s);
828 }
829 if (s - str > 64) {
830 fwrite(str, 1, s - str, stdout);
831 printf("\"\n\t.ascii \"");
832 str = s;
833 }
834 }
835 fwrite(str, 1, s - str, stdout);
836 printf("\\0\"\n");
837 }
838
839 /*
840 * print out a constant node, may be associated with a label.
841 * Do not free the node after use.
842 * off is bit offset from the beginning of the aggregate
843 * fsz is the number of bits this is referring to
844 */
845 int
846 ninval(CONSZ off, int fsz, NODE *p)
847 {
848 union { float f; double d; long double l; int i[3]; } u;
849 struct symtab *q;
850 char *c;
851 TWORD t;
852 int i;
853
854 t = p->n_type;
855 if (t > BTMASK)
856 p->n_type = t = INT; /* pointer */
857
858
859 if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) {
860 if (p->n_op == UMUL)
861 p = p->n_left;
862 p = p->n_right;
863 q = p->n_sp;
864
865 #if defined(ELFABI)
866
867 if (q->soname && (c = strstr(q->soname, "@got(31)")) != NULL)
868 *c = 0; /* ignore GOT ref here */
869
870 #elif defined(MACHOABI)
871
872 if ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) {
873 q->soname++; /* skip "L" */
874 *c = 0; /* ignore GOT ref here */
875 }
876 else if ((c = strstr(q->soname, "-L")) != NULL)
877 *c = 0; /* ignore GOT ref here */
878
879 #endif
880
881 }
882
883 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
884 uerror("element not constant");
885
886 switch (t) {
887 case LONGLONG:
888 case ULONGLONG:
889 #if 0
890 /* little-endian */
891 i = (p->n_lval >> 32);
892 p->n_lval &= 0xffffffff;
893 p->n_type = INT;
894 ninval(off, 32, p);
895 p->n_lval = i;
896 ninval(off+32, 32, p);
897 #endif
898 /* big-endian */
899 i = (p->n_lval & 0xffffffff);
900 p->n_lval >>= 32;
901 p->n_type = INT;
902 ninval(off, 32, p);
903 p->n_lval = i;
904 ninval(off+32, 32, p);
905
906 break;
907 case INT:
908 case UNSIGNED:
909 printf("\t.long %d", (int)p->n_lval);
910 if ((q = p->n_sp) != NULL) {
911 if ((q->sclass == STATIC && q->slevel > 0)) {
912 printf("+" LABFMT, q->soffset);
913 } else {
914 char *name = q->soname ? q->soname : exname(q->sname);
915 printf("+%s", name);
916 }
917 }
918 printf("\n");
919 break;
920 case LDOUBLE:
921 u.i[2] = 0;
922 u.l = (long double)p->n_dcon;
923 #if 0
924 /* little-endian */
925 printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
926 #endif
927 /* big-endian */
928 printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
929 break;
930 case DOUBLE:
931 u.d = (double)p->n_dcon;
932 printf("\t.long 0x%x\n\t.long 0x%x\n", u.i[0], u.i[1]);
933 break;
934 case FLOAT:
935 u.f = (float)p->n_dcon;
936 printf("\t.long 0x%x\n", u.i[0]);
937 break;
938 default:
939 return 0;
940 }
941 return 1;
942 }
943
944 /* make a name look like an external name in the local machine */
945 char *
946 exname(char *p)
947 {
948 #if defined(ELFABI)
949
950 return (p == NULL ? "" : p);
951
952 #elif defined(MACHOABI)
953
954 #define NCHNAM 256
955 static char text[NCHNAM+1];
956 int i;
957
958 if (p == NULL)
959 return "";
960
961 text[0] = '_';
962 for (i=1; *p && i<NCHNAM; ++i)
963 text[i] = *p++;
964
965 text[i] = '\0';
966 text[NCHNAM] = '\0'; /* truncate */
967
968 return (text);
969
970 #endif
971 }
972
973 /*
974 * map types which are not defined on the local machine
975 */
976 TWORD
977 ctype(TWORD type)
978 {
979 switch (BTYPE(type)) {
980 case LONG:
981 MODTYPE(type,INT);
982 break;
983
984 case ULONG:
985 MODTYPE(type,UNSIGNED);
986
987 }
988 return (type);
989 }
990
991 void
992 calldec(NODE *p, NODE *q)
993 {
994 #ifdef PCC_DEBUG
995 if (xdebug)
996 printf("calldec:\n");
997 #endif
998 }
999
1000 void
1001 extdec(struct symtab *q)
1002 {
1003 #ifdef PCC_DEBUG
1004 if (xdebug)
1005 printf("extdec:\n");
1006 #endif
1007 }
1008
1009 /* make a common declaration for id, if reasonable */
1010 void
1011 defzero(struct symtab *sp)
1012 {
1013 char *n;
1014 int off;
1015
1016 off = tsize(sp->stype, sp->sdf, sp->sap);
1017 off = (off+(SZCHAR-1))/SZCHAR;
1018 printf("\t.%scomm ", sp->sclass == STATIC ? "l" : "");
1019 n = sp->soname ? sp->soname : exname(sp->sname);
1020 if (sp->slevel == 0)
1021 printf("%s,%d\n", n, off);
1022 else
1023 printf(LABFMT ",%d\n", sp->soffset, off);
1024 }
1025
1026
1027 #ifdef notdef
1028 /* make a common declaration for id, if reasonable */
1029 void
1030 commdec(struct symtab *q)
1031 {
1032 int off;
1033
1034 off = tsize(q->stype, q->sdf, q->ssue);
1035 off = (off+(SZCHAR-1))/SZCHAR;
1036 printf("\t.comm %s,0%o\n", q->soname ? q->soname : exname(q->sname), off);
1037 }
1038
1039 /* make a local common declaration for id, if reasonable */
1040 void
1041 lcommdec(struct symtab *q)
1042 {
1043 int off;
1044
1045 off = tsize(q->stype, q->sdf, q->ssue);
1046 off = (off+(SZCHAR-1))/SZCHAR;
1047 if (q->slevel == 0)
1048 printf("\t.lcomm %s,%d\n", q->soname ? q->soname : exname(q->sname), off);
1049 else
1050 printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
1051 }
1052
1053 /*
1054 * print a (non-prog) label.
1055 */
1056 void
1057 deflab1(int label)
1058 {
1059 printf(LABFMT ":\n", label);
1060 }
1061
1062 #if defined(ELFABI)
1063
1064 static char *loctbl[] = { "text", "data", "section .rodata,",
1065 "section .rodata" };
1066
1067 #elif defined(MACHOABI)
1068
1069 static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" };
1070
1071 #endif
1072
1073 void
1074 setloc1(int locc)
1075 {
1076 #ifdef PCC_DEBUG
1077 if (xdebug)
1078 printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc);
1079 #endif
1080
1081 if (locc == lastloc)
1082 return;
1083 lastloc = locc;
1084 printf(" .%s\n", loctbl[locc]);
1085 }
1086 #endif
1087
1088 /* simulate and optimise the MOD opcode */
1089 static void
1090 simmod(NODE *p)
1091 {
1092 NODE *r = p->n_right;
1093
1094 assert(p->n_op == MOD);
1095
1096 if (!ISUNSIGNED(p->n_type))
1097 return;
1098
1099 #define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0))
1100
1101 /* if the right is a constant power of two, then replace with AND */
1102 if (r->n_op == ICON && ISPOW2(r->n_lval)) {
1103 p->n_op = AND;
1104 r->n_lval--;
1105 return;
1106 }
1107
1108 #undef ISPOW2
1109
1110 /* other optimizations can go here */
1111 }
1112
1113 static int constructor;
1114 static int destructor;
1115
1116 /*
1117 * Give target the opportunity of handling pragmas.
1118 */
1119 int
1120 mypragma(char *str)
1121 {
1122 if (strcmp(str, "tls") == 0) {
1123 uerror("thread-local storage not supported for this target");
1124 return 1;
1125 }
1126 if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
1127 constructor = 1;
1128 return 1;
1129 }
1130 if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
1131 destructor = 1;
1132 return 1;
1133 }
1134
1135 return 0;
1136 }
1137
1138 /*
1139 * Called when a identifier has been declared, to give target last word.
1140 */
1141 void
1142 fixdef(struct symtab *sp)
1143 {
1144 /* may have sanity checks here */
1145 if ((constructor || destructor) && (sp->sclass != PARAM)) {
1146 #ifdef MACHOABI
1147 if (kflag) {
1148 if (constructor)
1149 printf("\t.mod_init_func\n");
1150 else
1151 printf("\t.mod_term_func\n");
1152 } else {
1153 if (constructor)
1154 printf("\t.constructor\n");
1155 else
1156 printf("\t.destructor\n");
1157 }
1158 printf("\t.p2align 2\n");
1159 printf("\t.long %s\n", exname(sp->sname));
1160 printf("\t.text\n");
1161 constructor = destructor = 0;
1162 #endif
1163 }
1164 }
1165
1166 /*
1167 * There is very little different here to the standard builtins.
1168 * It basically handles promotion of types smaller than INT.
1169 */
1170
1171 NODE *
1172 powerpc_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
1173 {
1174 NODE *p, *q;
1175 int sz = 1;
1176
1177 /* check num args and type */
1178 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
1179 !ISPTR(a->n_left->n_type))
1180 goto bad;
1181
1182 /* must first deal with argument size; use int size */
1183 p = a->n_right;
1184 if (p->n_type < INT) {
1185 /* round up to word */
1186 sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
1187 }
1188
1189 p = buildtree(ADDROF, p, NIL); /* address of last arg */
1190 p = optim(buildtree(PLUS, p, bcon(sz)));
1191 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
1192 q = buildtree(CAST, q, p);
1193 p = q->n_right;
1194 nfree(q->n_left);
1195 nfree(q);
1196 p = buildtree(ASSIGN, a->n_left, p);
1197 tfree(f);
1198 nfree(a);
1199
1200 return p;
1201
1202 bad:
1203 uerror("bad argument to __builtin_stdarg_start");
1204 return bcon(0);
1205 }
1206
1207 NODE *
1208 powerpc_builtin_va_arg(NODE *f, NODE *a, TWORD t)
1209 {
1210 NODE *p, *q, *r;
1211 int sz, tmpnr;
1212
1213 /* check num args and type */
1214 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
1215 !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
1216 goto bad;
1217
1218 r = a->n_right;
1219
1220 /* get type size */
1221 sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
1222 if (sz < SZINT/SZCHAR) {
1223 werror("%s%s promoted to int when passed through ...",
1224 ISUNSIGNED(r->n_type) ? "unsigned " : "",
1225 DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
1226 sz = SZINT/SZCHAR;
1227 r->n_type = INT;
1228 r->n_ap = 0;
1229 }
1230
1231 p = tcopy(a->n_left);
1232
1233 #if defined(ELFABI)
1234
1235 /* alignment */
1236 if (SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
1237 p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
1238 p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap);
1239 }
1240
1241 #endif
1242
1243 /* create a copy to a temp node */
1244 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
1245 tmpnr = regno(q);
1246 p = buildtree(ASSIGN, q, p);
1247
1248 q = tempnode(tmpnr, p->n_type, p->n_df, p->n_ap);
1249 q = buildtree(PLUS, q, bcon(sz));
1250 q = buildtree(ASSIGN, a->n_left, q);
1251
1252 q = buildtree(COMOP, p, q);
1253
1254 nfree(a->n_right);
1255 nfree(a);
1256 nfree(f);
1257
1258 p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
1259 p = buildtree(UMUL, p, NIL);
1260 p = buildtree(COMOP, q, p);
1261
1262 return p;
1263
1264 bad:
1265 uerror("bad argument to __builtin_va_arg");
1266 return bcon(0);
1267 }
1268
1269 NODE *
1270 powerpc_builtin_va_end(NODE *f, NODE *a, TWORD t)
1271 {
1272 tfree(f);
1273 tfree(a);
1274
1275 return bcon(0);
1276 }
1277
1278 NODE *
1279 powerpc_builtin_va_copy(NODE *f, NODE *a, TWORD t)
1280 {
1281 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
1282 goto bad;
1283 tfree(f);
1284 f = buildtree(ASSIGN, a->n_left, a->n_right);
1285 nfree(a);
1286 return f;
1287
1288 bad:
1289 uerror("bad argument to __buildtin_va_copy");
1290 return bcon(0);
1291 }
1292
1293 NODE *
1294 powerpc_builtin_return_address(NODE *f, NODE *a, TWORD t)
1295 {
1296 int nframes;
1297 int i = 0;
1298
1299 if (a == NULL || a->n_op != ICON)
1300 goto bad;
1301
1302 nframes = a->n_lval;
1303
1304 tfree(f);
1305 tfree(a);
1306
1307 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1308 regno(f) = SPREG;
1309
1310 do {
1311 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1312 } while (i++ < nframes);
1313
1314 f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
1315 f = buildtree(UMUL, f, NIL);
1316
1317 return f;
1318 bad:
1319 uerror("bad argument to __builtin_return_address");
1320 return bcon(0);
1321 }
1322
1323 NODE *
1324 powerpc_builtin_frame_address(NODE *f, NODE *a, TWORD t)
1325 {
1326 int nframes;
1327 int i = 0;
1328
1329 if (a == NULL || a->n_op != ICON)
1330 goto bad;
1331
1332 nframes = a->n_lval;
1333
1334 tfree(f);
1335 tfree(a);
1336
1337 if (nframes == 0) {
1338 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1339 regno(f) = FPREG;
1340 } else {
1341 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1342 regno(f) = SPREG;
1343 do {
1344 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1345 } while (i++ < nframes);
1346 f = block(PLUS, f, bcon(24), INCREF(PTR+VOID), 0, 0);
1347 f = buildtree(UMUL, f, NIL);
1348 }
1349
1350 return f;
1351 bad:
1352 uerror("bad argument to __builtin_frame_address");
1353 return bcon(0);
1354 }
1355
1356 void
1357 pass1_lastchance(struct interpass *ip)
1358 {
1359 }
1360