* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / arch / i386 / local.c
blobdaab318c001faf64f93b683f1be91c732cc757d0
1 /* $Id: local.c,v 1.130.2.3 2011/03/30 16:35:36 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
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
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.
30 #include "pass1.h"
32 /* this file contains code which is dependent on the target machine */
34 #ifdef notyet
36 * Check if a constant is too large for a type.
38 static int
39 toolarge(TWORD t, CONSZ con)
41 U_CONSZ ucon = con;
43 switch (t) {
44 case ULONGLONG:
45 case LONGLONG:
46 break; /* cannot be too large */
47 #define SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break
48 #define UCHK(i) case i: if (ucon > MAX_##i) return 1; break
49 SCHK(INT);
50 SCHK(SHORT);
51 case BOOL:
52 SCHK(CHAR);
53 UCHK(UNSIGNED);
54 UCHK(USHORT);
55 UCHK(UCHAR);
56 default:
57 cerror("toolarge");
59 return 0;
61 #endif
63 #if defined(MACHOABI)
66 * Keep track of PIC stubs.
69 void
70 addstub(struct stub *list, char *name)
72 struct stub *s;
74 DLIST_FOREACH(s, list, link) {
75 if (strcmp(s->name, name) == 0)
76 return;
79 s = permalloc(sizeof(struct stub));
80 s->name = permalloc(strlen(name) + 1);
81 strcpy(s->name, name);
82 DLIST_INSERT_BEFORE(list, s, link);
85 #endif
87 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
90 * Make a symtab entry for PIC use.
92 static struct symtab *
93 picsymtab(char *p, char *s, char *s2)
95 struct symtab *sp = IALLOC(sizeof(struct symtab));
96 size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
98 sp->sname = sp->soname = IALLOC(len);
99 strlcpy(sp->soname, p, len);
100 strlcat(sp->soname, s, len);
101 strlcat(sp->soname, s2, len);
102 sp->sap = NULL;
103 sp->sclass = EXTERN;
104 sp->sflags = sp->slevel = 0;
105 return sp;
108 #ifdef os_win32
109 static NODE *
110 import(NODE *p)
112 NODE *q;
113 char *name;
114 struct symtab *sp;
116 if ((name = p->n_sp->soname) == NULL)
117 name = exname(p->n_sp->sname);
119 sp = picsymtab("__imp_", name, "");
120 q = xbcon(0, sp, PTR+VOID);
121 q = block(UMUL, q, 0, PTR|VOID, 0, MKAP(VOID));
122 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
123 q->n_sp = p->n_sp; /* for init */
124 nfree(p);
126 return q;
128 #endif
130 int gotnr; /* tempnum for GOT register */
131 int argstacksize;
134 * Create a reference for an extern variable.
136 static NODE *
137 picext(NODE *p)
140 #if defined(ELFABI)
142 NODE *q, *r;
143 struct symtab *sp;
144 char *name;
146 q = tempnode(gotnr, PTR|VOID, 0, MKAP(VOID));
147 if ((name = p->n_sp->soname) == NULL)
148 name = p->n_sp->sname;
149 sp = picsymtab("", name, "@GOT");
150 #ifdef GCC_COMPAT
151 if (attr_find(p->n_sp->sap, GCC_ATYP_STDCALL) != NULL)
152 p->n_sp->sflags |= SSTDCALL;
153 #endif
154 sp->sflags = p->n_sp->sflags & SSTDCALL;
155 r = xbcon(0, sp, INT);
156 q = buildtree(PLUS, q, r);
157 q = block(UMUL, q, 0, PTR|VOID, 0, MKAP(VOID));
158 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
159 q->n_sp = p->n_sp; /* for init */
160 nfree(p);
161 return q;
163 #elif defined(MACHOABI)
165 NODE *q, *r;
166 struct symtab *sp;
167 char buf2[256], *name, *pspn;
169 if ((name = cftnsp->soname) == NULL)
170 name = cftnsp->sname;
171 if ((pspn = p->n_sp->soname) == NULL)
172 pspn = exname(p->n_sp->sname);
173 if (p->n_sp->sclass == EXTDEF) {
174 snprintf(buf2, 256, "-L%s$pb", name);
175 sp = picsymtab("", pspn, buf2);
176 } else {
177 snprintf(buf2, 256, "$non_lazy_ptr-L%s$pb", name);
178 sp = picsymtab("L", pspn, buf2);
179 addstub(&nlplist, pspn);
181 q = tempnode(gotnr, PTR+VOID, 0, MKAP(VOID));
182 r = xbcon(0, sp, INT);
183 q = buildtree(PLUS, q, r);
185 if (p->n_sp->sclass != EXTDEF)
186 q = block(UMUL, q, 0, PTR+VOID, 0, MKAP(VOID));
187 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
188 q->n_sp = p->n_sp; /* for init */
189 nfree(p);
190 return q;
192 #elif defined(PECOFFABI)
194 return p;
196 #endif
201 * Create a reference for a static variable.
203 static NODE *
204 picstatic(NODE *p)
207 #if defined(ELFABI)
209 NODE *q, *r;
210 struct symtab *sp;
212 q = tempnode(gotnr, PTR|VOID, 0, MKAP(VOID));
213 if (p->n_sp->slevel > 0) {
214 char buf[32];
215 snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
216 sp = picsymtab("", buf, "@GOTOFF");
217 } else {
218 char *name;
219 if ((name = p->n_sp->soname) == NULL)
220 name = p->n_sp->sname;
221 sp = picsymtab("", name, "@GOTOFF");
224 sp->sclass = STATIC;
225 sp->stype = p->n_sp->stype;
226 r = xbcon(0, sp, INT);
227 q = buildtree(PLUS, q, r);
228 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
229 q->n_sp = p->n_sp; /* for init */
230 nfree(p);
231 return q;
233 #elif defined(MACHOABI)
235 NODE *q, *r;
236 struct symtab *sp;
237 char buf2[256];
239 snprintf(buf2, 256, "-L%s$pb",
240 cftnsp->soname ? cftnsp->soname : cftnsp->sname);
242 if (p->n_sp->slevel > 0) {
243 char buf1[32];
244 snprintf(buf1, 32, LABFMT, (int)p->n_sp->soffset);
245 sp = picsymtab("", buf1, buf2);
246 } else {
247 char *name;
248 if ((name = p->n_sp->soname) == NULL)
249 name = p->n_sp->sname;
250 sp = picsymtab("", exname(name), buf2);
252 sp->sclass = STATIC;
253 sp->stype = p->n_sp->stype;
254 q = tempnode(gotnr, PTR+VOID, 0, MKAP(VOID));
255 r = xbcon(0, sp, INT);
256 q = buildtree(PLUS, q, r);
257 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
258 q->n_sp = p->n_sp;
259 nfree(p);
260 return q;
262 #elif defined(PECOFFABI)
264 return p;
266 #endif
270 #ifdef TLS
272 * Create a reference for a TLS variable.
274 static NODE *
275 tlspic(NODE *p)
277 NODE *q, *r;
278 struct symtab *sp, *sp2;
279 char *name;
282 * creates:
283 * leal var@TLSGD(%ebx),%eax
284 * call ___tls_get_addr@PLT
287 /* calc address of var@TLSGD */
288 q = tempnode(gotnr, PTR|VOID, 0, MKAP(VOID));
289 if ((name = p->n_sp->soname) == NULL)
290 name = p->n_sp->sname;
291 sp = picsymtab("", name, "@TLSGD");
292 r = xbcon(0, sp, INT);
293 q = buildtree(PLUS, q, r);
295 /* assign to %eax */
296 r = block(REG, NIL, NIL, PTR|VOID, 0, MKAP(VOID));
297 r->n_rval = EAX;
298 q = buildtree(ASSIGN, r, q);
300 /* call ___tls_get_addr */
301 sp2 = lookup("___tls_get_addr@PLT", 0);
302 sp2->stype = EXTERN|INT|FTN;
303 r = nametree(sp2);
304 r = buildtree(ADDROF, r, NIL);
305 r = block(UCALL, r, NIL, INT, 0, MKAP(INT));
307 /* fusion both parts together */
308 q = buildtree(COMOP, q, r);
309 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
310 q->n_sp = p->n_sp; /* for init */
312 nfree(p);
313 return q;
316 static NODE *
317 tlsnonpic(NODE *p)
319 NODE *q, *r;
320 struct symtab *sp, *sp2;
321 int ext = p->n_sp->sclass;
322 char *name;
324 if ((name = p->n_sp->soname) == NULL)
325 name = p->n_sp->sname;
326 sp = picsymtab("", name,
327 ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF");
328 q = xbcon(0, sp, INT);
329 if (ext == EXTERN)
330 q = block(UMUL, q, NIL, PTR|VOID, 0, MKAP(VOID));
332 sp2 = lookup("%gs:0", 0);
333 sp2->stype = EXTERN|INT;
334 r = nametree(sp2);
336 q = buildtree(PLUS, q, r);
337 q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
338 q->n_sp = p->n_sp; /* for init */
340 nfree(p);
341 return q;
344 static NODE *
345 tlsref(NODE *p)
347 if (kflag)
348 return (tlspic(p));
349 else
350 return (tlsnonpic(p));
352 #endif
354 /* clocal() is called to do local transformations on
355 * an expression tree preparitory to its being
356 * written out in intermediate code.
358 * the major essential job is rewriting the
359 * automatic variables and arguments in terms of
360 * REG and OREG nodes
361 * conversion ops which are not necessary are also clobbered here
362 * in addition, any special features (such as rewriting
363 * exclusive or) are easily handled here as well
365 NODE *
366 clocal(NODE *p)
369 register struct symtab *q;
370 register NODE *r, *l;
371 #if defined(os_openbsd)
372 register NODE *s, *n;
373 #endif
374 register int o;
375 register int m;
377 #ifdef PCC_DEBUG
378 if (xdebug) {
379 printf("clocal: %p\n", p);
380 fwalk(p, eprint, 0);
382 #endif
383 switch( o = p->n_op ){
385 case NAME:
386 if ((q = p->n_sp) == NULL)
387 return p; /* Nothing to care about */
389 switch (q->sclass) {
391 case PARAM:
392 case AUTO:
393 /* fake up a structure reference */
394 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
395 r->n_lval = 0;
396 r->n_rval = FPREG;
397 p = stref(block(STREF, r, p, 0, 0, 0));
398 break;
400 case USTATIC:
401 if (kflag == 0)
402 break;
403 /* FALLTHROUGH */
404 case STATIC:
405 #ifdef TLS
406 if (q->sflags & STLS) {
407 p = tlsref(p);
408 break;
410 #endif
411 if (kflag == 0) {
412 if (q->slevel == 0)
413 break;
414 p->n_lval = 0;
415 } else if (blevel > 0)
416 p = picstatic(p);
417 break;
419 case REGISTER:
420 p->n_op = REG;
421 p->n_lval = 0;
422 p->n_rval = q->soffset;
423 break;
425 case EXTERN:
426 case EXTDEF:
427 #ifdef TLS
428 if (q->sflags & STLS) {
429 p = tlsref(p);
430 break;
432 #endif
434 #ifdef os_win32
435 if (q->sflags & SDLLINDIRECT)
436 p = import(p);
437 #endif
438 if (kflag == 0)
439 break;
440 if (blevel > 0)
441 p = picext(p);
442 break;
444 break;
446 case ADDROF:
447 if (kflag == 0 || blevel == 0)
448 break;
449 /* char arrays may end up here */
450 l = p->n_left;
451 if (l->n_op != NAME ||
452 (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
453 break;
454 l = p;
455 p = picstatic(p->n_left);
456 nfree(l);
457 if (p->n_op != UMUL)
458 cerror("ADDROF error");
459 l = p;
460 p = p->n_left;
461 nfree(l);
462 break;
464 case UCALL:
465 case USTCALL:
466 if (kflag == 0)
467 break;
468 #if defined(ELFABI)
469 /* Change to CALL node with ebx as argument */
470 l = block(REG, NIL, NIL, INT, 0, MKAP(INT));
471 l->n_rval = EBX;
472 p->n_right = buildtree(ASSIGN, l,
473 tempnode(gotnr, INT, 0, MKAP(INT)));
474 p->n_op -= (UCALL-CALL);
475 #endif
477 /* FALLTHROUGH */
478 #if defined(MACHOABI)
479 case CALL:
480 case STCALL:
481 if (p->n_type == VOID)
482 break;
484 r = tempnode(0, p->n_type, p->n_df, p->n_ap);
485 l = tcopy(r);
486 p = buildtree(COMOP, buildtree(ASSIGN, r, p), l);
487 #endif
489 break;
491 #ifdef notyet
492 /* XXX breaks sometimes */
493 case CBRANCH:
494 l = p->n_left;
497 * Remove unnecessary conversion ops.
499 if (!clogop(l->n_op) || l->n_left->n_op != SCONV)
500 break;
501 if (coptype(l->n_op) != BITYPE)
502 break;
503 if (l->n_right->n_op != ICON)
504 break;
505 r = l->n_left->n_left;
506 if (r->n_type >= FLOAT)
507 break;
508 if (toolarge(r->n_type, l->n_right->n_lval))
509 break;
510 l->n_right->n_type = r->n_type;
511 if (l->n_op >= ULE && l->n_op <= UGT)
512 l->n_op -= (UGT-ULE);
513 p->n_left = buildtree(l->n_op, r, l->n_right);
514 nfree(l->n_left);
515 nfree(l);
516 break;
517 #endif
519 case PCONV:
520 /* Remove redundant PCONV's. Be careful */
521 l = p->n_left;
522 if (l->n_op == ICON) {
523 l->n_lval = (unsigned)l->n_lval;
524 goto delp;
526 if (l->n_type < INT || l->n_type == LONGLONG ||
527 l->n_type == ULONGLONG) {
528 /* float etc? */
529 p->n_left = block(SCONV, l, NIL,
530 UNSIGNED, 0, MKAP(UNSIGNED));
531 break;
533 /* if left is SCONV, cannot remove */
534 if (l->n_op == SCONV)
535 break;
537 /* avoid ADDROF TEMP */
538 if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
539 break;
541 /* if conversion to another pointer type, just remove */
542 if (p->n_type > BTMASK && l->n_type > BTMASK)
543 goto delp;
544 break;
546 delp: l->n_type = p->n_type;
547 l->n_qual = p->n_qual;
548 l->n_df = p->n_df;
549 l->n_ap = p->n_ap;
550 nfree(p);
551 p = l;
552 break;
554 case SCONV:
555 if (p->n_left->n_op == COMOP)
556 break; /* may propagate wrong type later */
557 l = p->n_left;
559 if (p->n_type == l->n_type) {
560 nfree(p);
561 return l;
564 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
565 btattr[p->n_type].atypsz == btattr[l->n_type].atypsz) {
566 if (p->n_type != FLOAT && p->n_type != DOUBLE &&
567 l->n_type != FLOAT && l->n_type != DOUBLE &&
568 l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
569 if (l->n_op == NAME || l->n_op == UMUL ||
570 l->n_op == TEMP) {
571 l->n_type = p->n_type;
572 nfree(p);
573 return l;
578 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
579 coptype(l->n_op) == BITYPE && l->n_op != COMOP &&
580 l->n_op != QUEST) {
581 l->n_type = p->n_type;
582 nfree(p);
583 return l;
586 o = l->n_op;
587 m = p->n_type;
589 if (o == ICON) {
590 CONSZ val = l->n_lval;
592 if (!ISPTR(m)) /* Pointers don't need to be conv'd */
593 switch (m) {
594 case BOOL:
595 l->n_lval = nncon(l) ? (l->n_lval != 0) : 1;
596 l->n_sp = NULL;
597 break;
598 case CHAR:
599 l->n_lval = (char)val;
600 break;
601 case UCHAR:
602 l->n_lval = val & 0377;
603 break;
604 case SHORT:
605 l->n_lval = (short)val;
606 break;
607 case USHORT:
608 l->n_lval = val & 0177777;
609 break;
610 case ULONG:
611 case UNSIGNED:
612 l->n_lval = val & 0xffffffff;
613 break;
614 case LONG:
615 case INT:
616 l->n_lval = (int)val;
617 break;
618 case LONGLONG:
619 l->n_lval = (long long)val;
620 break;
621 case ULONGLONG:
622 l->n_lval = val;
623 break;
624 case VOID:
625 break;
626 case LDOUBLE:
627 case DOUBLE:
628 case FLOAT:
629 l->n_op = FCON;
630 l->n_dcon = val;
631 break;
632 default:
633 cerror("unknown type %d", m);
635 l->n_type = m;
636 l->n_ap = MKAP(m);
637 nfree(p);
638 return l;
639 } else if (l->n_op == FCON) {
640 l->n_lval = (CONSZ)l->n_dcon;
641 l->n_sp = NULL;
642 l->n_op = ICON;
643 l->n_type = m;
644 l->n_ap = MKAP(m);
645 nfree(p);
646 return clocal(l);
648 if (DEUNSIGN(p->n_type) == SHORT &&
649 DEUNSIGN(l->n_type) == SHORT) {
650 nfree(p);
651 p = l;
653 if ((p->n_type == CHAR || p->n_type == UCHAR ||
654 p->n_type == SHORT || p->n_type == USHORT) &&
655 (l->n_type == FLOAT || l->n_type == DOUBLE ||
656 l->n_type == LDOUBLE)) {
657 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
658 p->n_left->n_type = INT;
659 return p;
661 break;
663 case MOD:
664 case DIV:
665 if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
666 break;
667 if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
668 break;
669 /* make it an int division by inserting conversions */
670 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKAP(INT));
671 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKAP(INT));
672 p = block(SCONV, p, NIL, p->n_type, 0, MKAP(p->n_type));
673 p->n_left->n_type = INT;
674 break;
676 case PMCONV:
677 case PVCONV:
678 r = p;
679 p = buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
680 nfree(r);
681 break;
683 case FORCE:
684 /* put return value in return reg */
685 p->n_op = ASSIGN;
686 p->n_right = p->n_left;
687 p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
688 p->n_left->n_rval = p->n_left->n_type == BOOL ?
689 RETREG(CHAR) : RETREG(p->n_type);
690 break;
692 case LS:
693 case RS:
694 /* shift count must be in a char */
695 if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
696 break;
697 p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, MKAP(CHAR));
698 break;
699 #if defined(os_openbsd)
700 /* If not using pcc struct return */
701 case STASG:
702 r = p->n_right;
703 if (r->n_op != STCALL && r->n_op != USTCALL)
704 break;
705 m = tsize(BTYPE(r->n_type), r->n_df, r->n_ap);
706 if (m == SZCHAR)
707 m = CHAR;
708 else if (m == SZSHORT)
709 m = SHORT;
710 else if (m == SZINT)
711 m = INT;
712 else if (m == SZLONGLONG)
713 m = LONGLONG;
714 else
715 break;
717 l = buildtree(ADDROF, p->n_left, NIL);
718 nfree(p);
720 r->n_op -= (STCALL-CALL);
721 r->n_type = m;
723 /* r = long, l = &struct */
725 n = tempnode(0, m, r->n_df, r->n_ap);
726 r = buildtree(ASSIGN, ccopy(n), r);
728 s = tempnode(0, l->n_type, l->n_df, l->n_ap);
729 l = buildtree(ASSIGN, ccopy(s), l);
731 p = buildtree(COMOP, r, l);
733 l = buildtree(CAST,
734 block(NAME, NIL, NIL, m|PTR, 0, MKAP(m)), ccopy(s));
735 r = l->n_right;
736 nfree(l->n_left);
737 nfree(l);
739 r = buildtree(ASSIGN, buildtree(UMUL, r, NIL), n);
740 p = buildtree(COMOP, p, r);
741 p = buildtree(COMOP, p, s);
742 break;
743 #endif
745 #ifdef PCC_DEBUG
746 if (xdebug) {
747 printf("clocal end: %p\n", p);
748 fwalk(p, eprint, 0);
750 #endif
751 return(p);
755 * Change CALL references to either direct (static) or PLT.
757 static void
758 fixnames(NODE *p, void *arg)
760 #if !defined(PECOFFABI)
762 struct symtab *sp;
763 struct attr *ap;
764 NODE *q;
765 char *c;
766 int isu;
768 if ((cdope(p->n_op) & CALLFLG) == 0)
769 return;
770 isu = 0;
771 q = p->n_left;
772 ap = q->n_ap;
773 if (q->n_op == UMUL)
774 q = q->n_left, isu = 1;
776 if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
777 q->n_right->n_op == ICON) {
778 sp = q->n_right->n_sp;
780 if (sp == NULL)
781 return; /* nothing to do */
782 if (sp->sclass == STATIC && !ISFTN(sp->stype))
783 return; /* function pointer */
785 if (sp->sclass != STATIC && sp->sclass != EXTERN &&
786 sp->sclass != EXTDEF)
787 cerror("fixnames");
788 c = NULL;
789 #if defined(ELFABI)
791 if (sp->soname == NULL ||
792 (c = strstr(sp->soname, "@GOT")) == NULL)
793 cerror("fixnames2");
794 if (isu) {
795 memcpy(c, "@PLT", sizeof("@PLT"));
796 } else
797 *c = 0;
799 #elif defined(MACHOABI)
801 if (sp->soname == NULL ||
802 ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL &&
803 (c = strstr(sp->soname, "-L")) == NULL))
804 cerror("fixnames2");
805 if (isu) {
806 *c = 0;
807 addstub(&stublist, sp->soname+1);
808 strcpy(c, "$stub");
809 } else
810 *c = 0;
812 #endif
814 nfree(q->n_left);
815 q = q->n_right;
816 if (isu)
817 nfree(p->n_left->n_left);
818 nfree(p->n_left);
819 p->n_left = q;
820 q->n_ap = ap;
822 #endif
825 static void mangle(NODE *p);
827 void
828 myp2tree(NODE *p)
830 struct symtab *sp;
832 if (kflag)
833 fixnames(p, 0);
835 mangle(p);
837 if (p->n_op != FCON)
838 return;
840 sp = IALLOC(sizeof(struct symtab));
841 sp->sclass = STATIC;
842 sp->sap = MKAP(p->n_type);
843 sp->slevel = 1; /* fake numeric label */
844 sp->soffset = getlab();
845 sp->sflags = 0;
846 sp->stype = p->n_type;
847 sp->squal = (CON >> TSHIFT);
849 defloc(sp);
850 ninval(0, sp->sap->atypsz, p);
852 p->n_op = NAME;
853 p->n_lval = 0;
854 p->n_sp = sp;
857 /*ARGSUSED*/
859 andable(NODE *p)
861 return(1); /* all names can have & taken on them */
865 * at the end of the arguments of a ftn, set the automatic offset
867 void
868 cendarg()
870 autooff = AUTOINIT;
874 * Return 1 if a variable of type type is OK to put in register.
877 cisreg(TWORD t)
879 if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
880 return 0; /* not yet */
881 return 1;
885 * return a node, for structure references, which is suitable for
886 * being added to a pointer of type t, in order to be off bits offset
887 * into a structure
888 * t, d, and s are the type, dimension offset, and sizeoffset
889 * For pdp10, return the type-specific index number which calculation
890 * is based on its size. For example, short a[3] would return 3.
891 * Be careful about only handling first-level pointers, the following
892 * indirections must be fullword.
894 NODE *
895 offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap)
897 register NODE *p;
899 if (xdebug)
900 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
901 off, t, d, 0);
903 p = bcon(0);
904 p->n_lval = off/SZCHAR; /* Default */
905 return(p);
909 * Allocate off bits on the stack. p is a tree that when evaluated
910 * is the multiply count for off, t is a storeable node where to write
911 * the allocated address.
913 void
914 spalloc(NODE *t, NODE *p, OFFSZ off)
916 NODE *sp;
918 p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
920 /* sub the size from sp */
921 sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
922 sp->n_lval = 0;
923 sp->n_rval = STKREG;
924 ecomp(buildtree(MINUSEQ, sp, p));
926 #ifdef MACHOABI
927 /* align to 16 bytes */
928 sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
929 sp->n_lval = 0;
930 sp->n_rval = STKREG;
931 ecomp(buildtree(PLUSEQ, sp, bcon(15)));
933 sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
934 sp->n_lval = 0;
935 sp->n_rval = STKREG;
936 ecomp(buildtree(RSEQ, sp, bcon(4)));
938 sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
939 sp->n_lval = 0;
940 sp->n_rval = STKREG;
941 ecomp(buildtree(LSEQ, sp, bcon(4)));
942 #endif
945 /* save the address of sp */
946 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
947 sp->n_lval = 0;
948 sp->n_rval = STKREG;
949 t->n_type = sp->n_type;
950 ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
955 * Print out a string of characters.
956 * Assume that the assembler understands C-style escape
957 * sequences.
959 void
960 instring(struct symtab *sp)
962 char *s, *str = sp->sname;
964 #if defined(ELFABI) || defined(PECOFFABI)
966 defloc(sp);
968 #elif defined(MACHOABI)
970 extern int lastloc;
971 if (lastloc != STRNG)
972 printf(" .cstring\n");
973 lastloc = STRNG;
974 printf("\t.p2align 2\n");
975 printf(LABFMT ":\n", sp->soffset);
977 #endif
979 /* be kind to assemblers and avoid long strings */
980 printf("\t.ascii \"");
981 for (s = str; *s != 0; ) {
982 if (*s++ == '\\') {
983 (void)esccon(&s);
985 if (s - str > 60) {
986 fwrite(str, 1, s - str, stdout);
987 printf("\"\n\t.ascii \"");
988 str = s;
991 fwrite(str, 1, s - str, stdout);
992 printf("\\0\"\n");
995 static int inbits, inval;
998 * set fsz bits in sequence to zero.
1000 void
1001 zbits(OFFSZ off, int fsz)
1003 int m;
1005 if (idebug)
1006 printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
1007 if ((m = (inbits % SZCHAR))) {
1008 m = SZCHAR - m;
1009 if (fsz < m) {
1010 inbits += fsz;
1011 return;
1012 } else {
1013 fsz -= m;
1014 printf("\t.byte %d\n", inval);
1015 inval = inbits = 0;
1018 if (fsz >= SZCHAR) {
1019 #ifdef os_darwin
1020 printf("\t.space %d\n", fsz/SZCHAR);
1021 #else
1022 printf("\t.zero %d\n", fsz/SZCHAR);
1023 #endif
1024 fsz -= (fsz/SZCHAR) * SZCHAR;
1026 if (fsz) {
1027 inval = 0;
1028 inbits = fsz;
1033 * Initialize a bitfield.
1035 void
1036 infld(CONSZ off, int fsz, CONSZ val)
1038 if (idebug)
1039 printf("infld off %lld, fsz %d, val %lld inbits %d\n",
1040 off, fsz, val, inbits);
1041 val &= ((CONSZ)1 << fsz)-1;
1042 while (fsz + inbits >= SZCHAR) {
1043 inval |= (int)(val << inbits);
1044 printf("\t.byte %d\n", inval & 255);
1045 fsz -= (SZCHAR - inbits);
1046 val >>= (SZCHAR - inbits);
1047 inval = inbits = 0;
1049 if (fsz) {
1050 inval |= (int)(val << inbits);
1051 inbits += fsz;
1056 * print out a constant node, may be associated with a label.
1057 * Do not free the node after use.
1058 * off is bit offset from the beginning of the aggregate
1059 * fsz is the number of bits this is referring to
1061 void
1062 ninval(CONSZ off, int fsz, NODE *p)
1064 union { float f; double d; long double l; int i[3]; } u;
1065 struct symtab *q;
1066 #if defined(ELFABI) || defined(MACHOABI)
1067 char *c;
1068 #endif
1069 TWORD t;
1070 int i;
1072 t = p->n_type;
1073 if (t > BTMASK)
1074 t = INT; /* pointer */
1076 while (p->n_op == SCONV || p->n_op == PCONV) {
1077 NODE *l = p->n_left;
1078 l->n_type = p->n_type;
1079 p = l;
1082 if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) {
1083 if (p->n_op == UMUL)
1084 p = p->n_left;
1085 p = p->n_right;
1086 q = p->n_sp;
1088 if (q->soname != NULL) {
1089 #if defined(ELFABI)
1091 if ((c = strstr(q->soname, "@GOT")) != NULL)
1092 *c = 0; /* ignore GOT ref here */
1093 #elif defined(MACHOABI)
1095 if ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) {
1096 q->soname++; /* skip "L" */
1097 *c = 0; /* ignore GOT ref here */
1098 } else if ((c = strstr(q->soname, "-L")) != NULL)
1099 *c = 0; /* ignore GOT ref here */
1100 #endif
1103 if (p->n_op != ICON && p->n_op != FCON)
1104 cerror("ninval: init node not constant");
1106 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
1107 uerror("element not constant");
1109 switch (t) {
1110 case LONGLONG:
1111 case ULONGLONG:
1112 i = (int)(p->n_lval >> 32);
1113 p->n_lval &= 0xffffffff;
1114 p->n_type = INT;
1115 ninval(off, 32, p);
1116 p->n_lval = i;
1117 ninval(off+32, 32, p);
1118 break;
1119 case INT:
1120 case UNSIGNED:
1121 printf("\t.long %d", (int)p->n_lval);
1122 if ((q = p->n_sp) != NULL) {
1123 if ((q->sclass == STATIC && q->slevel > 0)) {
1124 printf("+" LABFMT, q->soffset);
1125 } else {
1126 char *name;
1127 if ((name = q->soname) == NULL)
1128 name = exname(q->sname);
1129 printf("+%s", name);
1132 printf("\n");
1133 break;
1134 case SHORT:
1135 case USHORT:
1136 #ifdef os_sunos
1137 printf("\t.2byte 0x%x\n", (int)p->n_lval & 0xffff);
1138 #else
1139 printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
1140 #endif
1141 break;
1142 case BOOL:
1143 if (p->n_lval > 1)
1144 p->n_lval = p->n_lval != 0;
1145 /* FALLTHROUGH */
1146 case CHAR:
1147 case UCHAR:
1148 printf("\t.byte %d\n", (int)p->n_lval & 0xff);
1149 break;
1150 case LDOUBLE:
1151 u.i[2] = 0;
1152 u.l = (long double)p->n_dcon;
1153 #if defined(HOST_BIG_ENDIAN)
1154 /* XXX probably broken on most hosts */
1155 printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
1156 #else
1157 printf("\t.long\t%d,%d,%d\n", u.i[0], u.i[1], u.i[2] & 0177777);
1158 #endif
1159 break;
1160 case DOUBLE:
1161 u.d = (double)p->n_dcon;
1162 #if defined(HOST_BIG_ENDIAN)
1163 printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
1164 #else
1165 printf("\t.long\t%d,%d\n", u.i[0], u.i[1]);
1166 #endif
1167 break;
1168 case FLOAT:
1169 u.f = (float)p->n_dcon;
1170 printf("\t.long\t%d\n", u.i[0]);
1171 break;
1172 default:
1173 cerror("ninval");
1177 /* make a name look like an external name in the local machine */
1178 char *
1179 exname(char *p)
1181 #if defined(PECOFFABI) || defined(MACHOABI)
1183 #define NCHNAM 256
1184 static char text[NCHNAM+1];
1185 int i;
1187 if (p == NULL)
1188 return "";
1190 text[0] = '_';
1191 for (i=1; *p && i<NCHNAM; ++i)
1192 text[i] = *p++;
1194 text[i] = '\0';
1195 text[NCHNAM] = '\0'; /* truncate */
1197 return (text);
1199 #else
1201 return (p == NULL ? "" : p);
1203 #endif
1207 * map types which are not defined on the local machine
1209 TWORD
1210 ctype(TWORD type)
1212 switch (BTYPE(type)) {
1213 case LONG:
1214 MODTYPE(type,INT);
1215 break;
1217 case ULONG:
1218 MODTYPE(type,UNSIGNED);
1221 return (type);
1224 void
1225 calldec(NODE *p, NODE *q)
1229 void
1230 extdec(struct symtab *q)
1234 /* make a common declaration for id, if reasonable */
1235 void
1236 defzero(struct symtab *sp)
1238 int off;
1239 int al;
1240 char *name;
1242 #ifdef TLS
1243 if (sp->sflags & STLS) {
1244 if (sp->sclass == EXTERN)
1245 sp->sclass = EXTDEF;
1246 simpleinit(sp, bcon(0));
1247 return;
1249 #endif
1251 if ((name = sp->soname) == NULL)
1252 name = exname(sp->sname);
1253 al = talign(sp->stype, sp->sap)/SZCHAR;
1254 off = (int)tsize(sp->stype, sp->sdf, sp->sap);
1255 off = (off+(SZCHAR-1))/SZCHAR;
1256 #ifdef GCC_COMPAT
1258 struct attr *ap;
1259 if ((ap = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) &&
1260 strcmp(ap->sarg(0), "default"))
1261 printf("\t.%s %s\n", ap->sarg(0), name);
1263 #endif
1264 printf(" .%scomm ", sp->sclass == STATIC ? "l" : "");
1265 if (sp->slevel == 0)
1266 printf("%s,0%o", name, off);
1267 else
1268 printf(LABFMT ",0%o", sp->soffset, off);
1269 if (sp->sclass != STATIC) {
1270 #if defined(ELFABI)
1271 printf(",%d", al);
1272 #elif defined(MACHOABI)
1273 printf(",%d", ispow2(al));
1274 #endif
1276 printf("\n");
1279 static char *
1280 section2string(char *name, int len)
1282 #if defined(ELFABI)
1283 char *s;
1284 int n;
1286 if (strncmp(name, "link_set", 8) == 0) {
1287 const char *postfix = ",\"aw\",@progbits";
1288 n = len + strlen(postfix) + 1;
1289 s = IALLOC(n);
1290 strlcpy(s, name, n);
1291 strlcat(s, postfix, n);
1292 return s;
1294 #endif
1296 return newstring(name, len);
1299 char *nextsect;
1300 #ifdef TLS
1301 static int gottls;
1302 #endif
1303 static int stdcall;
1304 #ifdef os_win32
1305 static int dllindirect;
1306 #endif
1307 static char *alias;
1308 static int constructor;
1309 static int destructor;
1312 * Give target the opportunity of handling pragmas.
1315 mypragma(char *str)
1317 char *a2 = pragtok(NULL);
1319 #ifdef TLS
1320 if (strcmp(str, "tls") == 0 && a2 == NULL) {
1321 gottls = 1;
1322 return 1;
1324 #endif
1325 if (strcmp(str, "stdcall") == 0) {
1326 stdcall = 1;
1327 return 1;
1329 if (strcmp(str, "cdecl") == 0) {
1330 stdcall = 0;
1331 return 1;
1333 #ifdef os_win32
1334 if (strcmp(str, "fastcall") == 0) {
1335 stdcall = 2;
1336 return 1;
1338 if (strcmp(str, "dllimport") == 0) {
1339 dllindirect = 1;
1340 return 1;
1342 if (strcmp(str, "dllexport") == 0) {
1343 dllindirect = 1;
1344 return 1;
1346 #endif
1347 if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
1348 constructor = 1;
1349 return 1;
1351 if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
1352 destructor = 1;
1353 return 1;
1355 if (strcmp(str, "section") == 0 && a2 != NULL) {
1356 nextsect = section2string(a2, strlen(a2));
1357 return 1;
1359 if (strcmp(str, "alias") == 0 && a2 != NULL) {
1360 alias = tmpstrdup(a2);
1361 return 1;
1363 if (strcmp(str, "ident") == 0)
1364 return 1; /* Just ignore */
1366 return 0;
1370 * Called when a identifier has been declared.
1372 void
1373 fixdef(struct symtab *sp)
1375 struct attr *ap;
1376 #ifdef TLS
1377 /* may have sanity checks here */
1378 if (gottls)
1379 sp->sflags |= STLS;
1380 gottls = 0;
1381 #endif
1382 if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
1383 char *an = ap->sarg(0);
1384 char *sn = sp->soname ? sp->soname : sp->sname;
1385 char *v;
1387 v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
1388 printf("\t.%s %s\n", v, sn);
1389 printf("\t.set %s,%s\n", sn, an);
1392 if (alias != NULL && (sp->sclass != PARAM)) {
1393 char *name;
1394 if ((name = sp->soname) == NULL)
1395 name = exname(sp->sname);
1396 printf("\t.globl %s\n", name);
1397 printf("%s = ", name);
1398 printf("%s\n", exname(alias));
1399 alias = NULL;
1401 if ((constructor || destructor) && (sp->sclass != PARAM)) {
1402 #if defined(ELFABI)
1403 printf("\t.section .%ctors,\"aw\",@progbits\n",
1404 constructor ? 'c' : 'd');
1405 #elif defined(PECOFFABI)
1406 printf("\t.section .%ctors,\"w\"\n",
1407 constructor ? 'c' : 'd');
1408 #elif defined(MACHOABI)
1409 if (kflag) {
1410 if (constructor)
1411 printf("\t.mod_init_func\n");
1412 else
1413 printf("\t.mod_term_func\n");
1414 } else {
1415 if (constructor)
1416 printf("\t.constructor\n");
1417 else
1418 printf("\t.destructor\n");
1420 #endif
1421 printf("\t.p2align 2\n");
1422 printf("\t.long %s\n", exname(sp->sname));
1423 #ifdef MACHOABI
1424 printf("\t.text\n");
1425 #else
1426 printf("\t.previous\n");
1427 #endif
1428 constructor = destructor = 0;
1430 if (stdcall && (sp->sclass != PARAM)) {
1431 sp->sflags |= SSTDCALL;
1432 stdcall = 0;
1434 #ifdef os_win32
1435 if (dllindirect && (sp->sclass != PARAM)) {
1436 sp->sflags |= SDLLINDIRECT;
1437 dllindirect = 0;
1439 #endif
1442 NODE *
1443 i386_builtin_return_address(NODE *f, NODE *a, TWORD rt)
1445 int nframes;
1447 if (a == NULL || a->n_op != ICON)
1448 goto bad;
1450 nframes = (int)a->n_lval;
1452 tfree(f);
1453 tfree(a);
1455 f = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
1456 regno(f) = FPREG;
1458 while (nframes--)
1459 f = block(UMUL, f, NIL, PTR+VOID, 0, MKAP(VOID));
1461 f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, MKAP(VOID));
1462 f = buildtree(UMUL, f, NIL);
1464 return f;
1465 bad:
1466 uerror("bad argument to __builtin_return_address");
1467 return bcon(0);
1470 NODE *
1471 i386_builtin_frame_address(NODE *f, NODE *a, TWORD rt)
1473 int nframes;
1475 if (a == NULL || a->n_op != ICON)
1476 goto bad;
1478 nframes = (int)a->n_lval;
1480 tfree(f);
1481 tfree(a);
1483 f = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
1484 regno(f) = FPREG;
1486 while (nframes--)
1487 f = block(UMUL, f, NIL, PTR+VOID, 0, MKAP(VOID));
1489 return f;
1490 bad:
1491 uerror("bad argument to __builtin_frame_address");
1492 return bcon(0);
1496 * Postfix external functions with the arguments size.
1498 static void
1499 mangle(NODE *p)
1501 NODE *l;
1503 if (p->n_op == NAME || p->n_op == ICON) {
1504 p->n_flags = 0; /* for later setting of STDCALL */
1505 if (p->n_sp) {
1506 if (p->n_sp->sflags & SSTDCALL)
1507 p->n_flags = FSTDCALL;
1509 } else if (p->n_op == TEMP)
1510 p->n_flags = 0; /* STDCALL fun ptr not allowed */
1512 if (p->n_op != CALL && p->n_op != STCALL &&
1513 p->n_op != UCALL && p->n_op != USTCALL)
1514 return;
1516 p->n_flags = 0;
1518 l = p->n_left;
1519 while (cdope(l->n_op) & CALLFLG)
1520 l = l->n_left;
1521 if (l->n_op == TEMP)
1522 return;
1523 if (l->n_op == ADDROF)
1524 l = l->n_left;
1525 if (l->n_sp == NULL)
1526 return;
1527 #ifdef GCC_COMPAT
1528 if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL) != NULL)
1529 l->n_sp->sflags |= SSTDCALL;
1530 #endif
1531 #ifdef os_win32
1532 if (l->n_sp->sflags & SSTDCALL) {
1533 if (strchr(l->n_name, '@') == NULL) {
1534 int size = 0;
1535 char buf[256];
1536 NODE *r;
1537 TWORD t;
1539 if (p->n_op == CALL || p->n_op == STCALL) {
1540 for (r = p->n_right;
1541 r->n_op == CM; r = r->n_left) {
1542 t = r->n_type;
1543 if (t == STRTY || t == UNIONTY)
1544 size += tsize(t, r->n_df, r->n_ap);
1545 else
1546 size += szty(t) * SZINT / SZCHAR;
1548 t = r->n_type;
1549 if (t == STRTY || t == UNIONTY)
1550 size += tsize(t, r->n_df, r->n_ap);
1551 else
1552 size += szty(t) * SZINT / SZCHAR;
1554 snprintf(buf, 256, "%s@%d", l->n_name, size);
1555 l->n_name = IALLOC(strlen(buf) + 1);
1556 strcpy(l->n_name, buf);
1559 #endif
1562 void
1563 pass1_lastchance(struct interpass *ip)
1565 if (ip->type == IP_NODE &&
1566 (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) &&
1567 ISFTY(ip->ip_node->n_type))
1568 ip->ip_node->n_flags = FFPPOP;
1570 if (ip->type == IP_EPILOG) {
1571 struct interpass_prolog *ipp = (struct interpass_prolog *)ip;
1572 ipp->ipp_argstacksize = argstacksize;