source: mainline/uspace/app/pcc/arch/powerpc/local.c@ 5974661

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