1 /* Id: local.c,v 1.37 2015/12/31 16:21:57 ragge Exp */
2 /* $NetBSD: local.c,v 1.1.1.6 2016/02/09 20:28:21 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 /*
29 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
30 * Simon Olsson (simols-1@student.ltu.se) 2005.
31 */
32
33 #include "pass1.h"
34
35 #ifndef LANG_CXX
36 #define NODE P1ND
37 #define ccopy p1tcopy
38 #define tcopy p1tcopy
39 #define tfree p1tfree
40 #define nfree p1nfree
41 #define fwalk p1fwalk
42 #define talloc p1alloc
43 #endif
44
45 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
46
47 /* this is called to do local transformations on
48 * an expression tree preparitory to its being
49 * written out in intermediate code.
50 */
51 NODE *
clocal(NODE * p)52 clocal(NODE *p)
53 {
54 struct symtab *q;
55 NODE *r, *l;
56 int o;
57 int m;
58 TWORD ty;
59 int tmpnr, isptrvoid = 0;
60
61 #ifdef PCC_DEBUG
62 if (xdebug) {
63 printf("clocal in: %p\n", p);
64 fwalk(p, eprint, 0);
65 }
66 #endif
67
68 switch (o = p->n_op) {
69
70 case UCALL:
71 case CALL:
72 case STCALL:
73 case USTCALL:
74 if (p->n_type == VOID)
75 break;
76 /*
77 * if the function returns void*, ecode() invokes
78 * delvoid() to convert it to uchar*.
79 * We just let this happen on the ASSIGN to the temp,
80 * and cast the pointer back to void* on access
81 * from the temp.
82 */
83 if (p->n_type == PTR+VOID)
84 isptrvoid = 1;
85 r = tempnode(0, p->n_type, p->n_df, p->n_ap);
86 tmpnr = regno(r);
87 r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
88
89 p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
90 if (isptrvoid) {
91 p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0);
92 }
93 p = buildtree(COMOP, r, p);
94 break;
95
96 case NAME:
97 if ((q = p->n_sp) == NULL)
98 return p; /* Nothing to care about */
99
100 switch (q->sclass) {
101
102 case PARAM:
103 case AUTO:
104 /* fake up a structure reference */
105 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
106 slval(r, 0);
107 r->n_rval = FP;
108 p = stref(block(STREF, r, p, 0, 0, 0));
109 break;
110
111 case STATIC:
112 if (q->slevel == 0)
113 break;
114 slval(p, 0);
115 p->n_sp = q;
116 break;
117
118 case REGISTER:
119 p->n_op = REG;
120 slval(p, 0);
121 p->n_rval = q->soffset;
122 break;
123
124 }
125 break;
126
127 case FUNARG:
128 /* Args smaller than int are given as int */
129 if (p->n_type != CHAR && p->n_type != UCHAR &&
130 p->n_type != SHORT && p->n_type != USHORT)
131 break;
132 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
133 p->n_type = INT;
134 p->n_ap = 0;
135 p->n_rval = SZINT;
136 break;
137
138 case CBRANCH:
139 l = p->n_left;
140
141 /*
142 * Remove unnecessary conversion ops.
143 */
144 if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
145 if (coptype(l->n_op) != BITYPE)
146 break;
147 if (l->n_right->n_op == ICON) {
148 r = l->n_left->n_left;
149 if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
150 break;
151 /* Type must be correct */
152 ty = r->n_type;
153 nfree(l->n_left);
154 l->n_left = r;
155 l->n_type = ty;
156 l->n_right->n_type = ty;
157 }
158 #if 0
159 else if (l->n_right->n_op == SCONV &&
160 l->n_left->n_type == l->n_right->n_type) {
161 r = l->n_left->n_left;
162 nfree(l->n_left);
163 l->n_left = r;
164 r = l->n_right->n_left;
165 nfree(l->n_right);
166 l->n_right = r;
167 }
168 #endif
169 }
170 break;
171
172 case PCONV:
173 /* Remove redundant PCONV's. Be careful */
174 l = p->n_left;
175 if (l->n_op == ICON) {
176 slval(l, (unsigned)glval(l));
177 goto delp;
178 }
179 if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
180 /* float etc? */
181 p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
182 break;
183 }
184 /* if left is SCONV, cannot remove */
185 if (l->n_op == SCONV)
186 break;
187
188 /* avoid ADDROF TEMP */
189 if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
190 break;
191
192 /* if conversion to another pointer type, just remove */
193 if (p->n_type > BTMASK && l->n_type > BTMASK)
194 goto delp;
195 break;
196
197 delp: l->n_type = p->n_type;
198 l->n_qual = p->n_qual;
199 l->n_df = p->n_df;
200 l->n_ap = p->n_ap;
201 nfree(p);
202 p = l;
203 break;
204
205 case SCONV:
206 l = p->n_left;
207
208 if (p->n_type == l->n_type) {
209 nfree(p);
210 p = l;
211 break;
212 }
213
214 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
215 tsize(p->n_type, p->n_df, p->n_ap) ==
216 tsize(l->n_type, l->n_df, l->n_ap)) {
217 if (p->n_type != FLOAT && p->n_type != DOUBLE &&
218 l->n_type != FLOAT && l->n_type != DOUBLE &&
219 l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
220 if (l->n_op == NAME || l->n_op == UMUL ||
221 l->n_op == TEMP) {
222 l->n_type = p->n_type;
223 nfree(p);
224 p = l;
225 break;
226 }
227 }
228 }
229
230 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
231 coptype(l->n_op) == BITYPE) {
232 l->n_type = p->n_type;
233 nfree(p);
234 p = l;
235 }
236
237 if (DEUNSIGN(p->n_type) == SHORT &&
238 DEUNSIGN(l->n_type) == SHORT) {
239 nfree(p);
240 p = l;
241 }
242
243 /* convert float/double to int before to (u)char/(u)short */
244 if ((DEUNSIGN(p->n_type) == CHAR ||
245 DEUNSIGN(p->n_type) == SHORT) &&
246 (l->n_type == FLOAT || l->n_type == DOUBLE ||
247 l->n_type == LDOUBLE)) {
248 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
249 p->n_left->n_type = INT;
250 break;
251 }
252
253 /* convert (u)char/(u)short to int before float/double */
254 if ((p->n_type == FLOAT || p->n_type == DOUBLE ||
255 p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
256 DEUNSIGN(l->n_type) == SHORT)) {
257 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
258 p->n_left->n_type = INT;
259 break;
260 }
261
262 o = l->n_op;
263 m = p->n_type;
264
265 if (o == ICON) {
266 CONSZ val = glval(l);
267
268 if (!ISPTR(m)) /* Pointers don't need to be conv'd */
269 switch (m) {
270 case BOOL:
271 val = nncon(l) ? (val != 0) : 1;
272 slval(l, val);
273 l->n_sp = NULL;
274 break;
275 case CHAR:
276 slval(l, (char)val);
277 break;
278 case UCHAR:
279 slval(l, val & 0377);
280 break;
281 case SHORT:
282 slval(l, (short)val);
283 break;
284 case USHORT:
285 slval(l, val & 0177777);
286 break;
287 case ULONG:
288 case UNSIGNED:
289 slval(l, val & 0xffffffff);
290 break;
291 case LONG:
292 case INT:
293 slval(l, (int)val);
294 break;
295 case LONGLONG:
296 slval(l, (long long)val);
297 break;
298 case ULONGLONG:
299 slval(l, val);
300 break;
301 case VOID:
302 break;
303 case LDOUBLE:
304 case DOUBLE:
305 case FLOAT:
306 l->n_op = FCON;
307 l->n_dcon = tmpalloc(sizeof(union flt));
308 ((union flt *)l->n_dcon)->fp = val;
309 break;
310 default:
311 cerror("unknown type %d", m);
312 }
313 l->n_type = m;
314 nfree(p);
315 p = l;
316 } else if (o == FCON) {
317 CONSZ lv;
318 if (p->n_type == BOOL)
319 lv = !FLOAT_ISZERO(((union flt *)l->n_dcon));
320 else {
321 FLOAT_FP2INT(lv, ((union flt *)l->n_dcon), m);
322 }
323 slval(l, lv);
324 l->n_sp = NULL;
325 l->n_op = ICON;
326 l->n_type = m;
327 l->n_ap = 0;
328 nfree(p);
329 p = clocal(l);
330 }
331 break;
332
333 case MOD:
334 case DIV:
335 if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
336 break;
337 if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
338 break;
339 /* make it an int division by inserting conversions */
340 p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
341 p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
342 p = block(SCONV, p, NIL, p->n_type, 0, 0);
343 p->n_left->n_type = INT;
344 break;
345
346 case FORCE:
347 /* put return value in return reg */
348 p->n_op = ASSIGN;
349 p->n_right = p->n_left;
350 p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
351 p->n_left->n_rval = RETREG(p->n_type);
352 break;
353 }
354
355 #ifdef PCC_DEBUG
356 if (xdebug) {
357 printf("clocal out: %p\n", p);
358 fwalk(p, eprint, 0);
359 }
360 #endif
361
362 return(p);
363 }
364
365 void
myp2tree(NODE * p)366 myp2tree(NODE *p)
367 {
368 struct symtab *sp;
369
370 if (p->n_op != FCON)
371 return;
372
373 /* Write float constants to memory */
374
375 sp = IALLOC(sizeof(struct symtab));
376 sp->sclass = STATIC;
377 sp->sap = 0;
378 sp->slevel = 1; /* fake numeric label */
379 sp->soffset = getlab();
380 sp->sflags = 0;
381 sp->stype = p->n_type;
382 sp->squal = (CON >> TSHIFT);
383
384 defloc(sp);
385 ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
386
387 p->n_op = NAME;
388 slval(p, 0);
389 p->n_sp = sp;
390
391 }
392
393 /*ARGSUSED*/
394 int
andable(NODE * p)395 andable(NODE *p)
396 {
397 return(1); /* all names can have & taken on them */
398 }
399
400 /*
401 * is an automatic variable of type t OK for a register variable
402 */
403 int
cisreg(TWORD t)404 cisreg(TWORD t)
405 {
406 if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
407 return(1);
408 return 0; /* XXX - fix reg assignment in pftn.c */
409 }
410
411 /*
412 * Allocate off bits on the stack. p is a tree that when evaluated
413 * is the multiply count for off, t is a NAME node where to write
414 * the allocated address.
415 */
416 void
spalloc(NODE * t,NODE * p,OFFSZ off)417 spalloc(NODE *t, NODE *p, OFFSZ off)
418 {
419 NODE *sp;
420 int nbytes = off / SZCHAR;
421
422 p = buildtree(MUL, p, bcon(nbytes));
423 p = buildtree(PLUS, p, bcon(7));
424 p = buildtree(AND, p, bcon(~7));
425
426 /* subtract the size from sp */
427 sp = block(REG, NIL, NIL, p->n_type, 0, 0);
428 slval(sp, 0);
429 sp->n_rval = SP;
430 ecomp(buildtree(MINUSEQ, sp, p));
431
432 /* save the address of sp */
433 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
434 sp->n_rval = SP;
435 t->n_type = sp->n_type;
436 ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
437 }
438
439 /*
440 * print out a constant node
441 * mat be associated with a label
442 */
443 int
ninval(CONSZ off,int fsz,NODE * p)444 ninval(CONSZ off, int fsz, NODE *p)
445 {
446 union { float f; double d; int i[2]; } u;
447 struct symtab *q;
448 TWORD t;
449 #ifndef USE_GAS
450 int i, j;
451 #endif
452
453 t = p->n_type;
454 if (t > BTMASK)
455 p->n_type = t = INT; /* pointer */
456
457 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
458 uerror("element not constant");
459
460 switch (t) {
461 case LONGLONG:
462 case ULONGLONG:
463 #ifdef USE_GAS
464 printf("\t.dword %lld\n", (long long)glval(p));
465 #else
466 i = glval(p) >> 32;
467 j = glval(p) & 0xffffffff;
468 p->n_type = INT;
469 if (bigendian) {
470 slval(p, j);
471 ninval(off, 32, p);
472 slval(p, i);
473 ninval(off+32, 32, p);
474 } else {
475 slval(p, i);
476 ninval(off, 32, p);
477 slval(p, j);
478 ninval(off+32, 32, p);
479 }
480 #endif
481 break;
482 case INT:
483 case UNSIGNED:
484 printf("\t.word " CONFMT, (CONSZ)glval(p));
485 if ((q = p->n_sp) != NULL) {
486 if ((q->sclass == STATIC && q->slevel > 0)) {
487 printf("+" LABFMT, q->soffset);
488 } else
489 printf("+%s", getexname(q));
490 }
491 printf("\n");
492 break;
493 case SHORT:
494 case USHORT:
495 astypnames[SHORT] = astypnames[USHORT] = "\t.half";
496 return 0;
497 case LDOUBLE:
498 case DOUBLE:
499 u.d = (double)((union flt *)p->n_dcon)->fp;
500 if (bigendian) {
501 printf("\t.word\t%d\n", u.i[0]);
502 printf("\t.word\t%d\n", u.i[1]);
503 } else {
504 printf("\t.word\t%d\n", u.i[1]);
505 printf("\t.word\t%d\n", u.i[0]);
506 }
507 break;
508 case FLOAT:
509 u.f = (float)((union flt *)p->n_dcon)->fp;
510 printf("\t.word\t0x%x\n", u.i[0]);
511 break;
512 default:
513 return 0;
514 }
515 return 1;
516 }
517
518 /* make a name look like an external name in the local machine */
519 char *
exname(char * p)520 exname(char *p)
521 {
522 if (p == NULL)
523 return "";
524 return p;
525 }
526
527 /*
528 * map types which are not defined on the local machine
529 */
530 TWORD
ctype(TWORD type)531 ctype(TWORD type)
532 {
533 switch (BTYPE(type)) {
534 case LONG:
535 MODTYPE(type,INT);
536 break;
537
538 case ULONG:
539 MODTYPE(type,UNSIGNED);
540
541 }
542 return (type);
543 }
544
545 void
calldec(NODE * p,NODE * q)546 calldec(NODE *p, NODE *q)
547 {
548 }
549
550 void
extdec(struct symtab * q)551 extdec(struct symtab *q)
552 {
553 }
554
555 /* make a common declaration for id, if reasonable */
556 void
defzero(struct symtab * sp)557 defzero(struct symtab *sp)
558 {
559 int off;
560
561 off = tsize(sp->stype, sp->sdf, sp->sap);
562 off = (off+(SZCHAR-1))/SZCHAR;
563 printf(" .%scomm ", sp->sclass == STATIC ? "l" : "");
564 if (sp->slevel == 0)
565 printf("%s,0%o\n", getexname(sp), off);
566 else
567 printf(LABFMT ",0%o\n", sp->soffset, off);
568 }
569
570
571 #ifdef notdef
572 /* make a common declaration for id, if reasonable */
573 void
commdec(struct symtab * q)574 commdec(struct symtab *q)
575 {
576 int off;
577
578 off = tsize(q->stype, q->sdf, q->ssue);
579 off = (off+(SZCHAR-1))/SZCHAR;
580
581 printf(" .comm %s,%d\n", exname(q->soname), off);
582 }
583
584 /* make a local common declaration for id, if reasonable */
585 void
lcommdec(struct symtab * q)586 lcommdec(struct symtab *q)
587 {
588 int off;
589
590 off = tsize(q->stype, q->sdf, q->ssue);
591 off = (off+(SZCHAR-1))/SZCHAR;
592 if (q->slevel == 0)
593 printf("\t.lcomm %s,%d\n", exname(q->soname), off);
594 else
595 printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
596 }
597
598 /*
599 * print a (non-prog) label.
600 */
601 void
deflab1(int label)602 deflab1(int label)
603 {
604 printf(LABFMT ":\n", label);
605 }
606
607 /* ro-text, rw-data, ro-data, ro-strings */
608 static char *loctbl[] = { "text", "data", "rdata", "rdata" };
609
610 void
setloc1(int locc)611 setloc1(int locc)
612 {
613 if (locc == lastloc && locc != STRNG)
614 return;
615 if (locc == RDATA && lastloc == STRNG)
616 return;
617
618 if (locc != lastloc) {
619 lastloc = locc;
620 printf("\t.%s\n", loctbl[locc]);
621 }
622
623 if (locc == STRNG)
624 printf("\t.align 2\n");
625 }
626 #endif
627
628 /*
629 * va_start(ap, last) implementation.
630 *
631 * f is the NAME node for this builtin function.
632 * a is the argument list containing:
633 * CM
634 * ap last
635 *
636 * It turns out that this is easy on MIPS. Just write the
637 * argument registers to the stack in va_arg_start() and
638 * use the traditional method of walking the stackframe.
639 */
640 NODE *
mips_builtin_stdarg_start(const struct bitable * bt,NODE * a)641 mips_builtin_stdarg_start(const struct bitable *bt, NODE *a)
642 {
643 NODE *p, *q;
644 int sz = 1;
645
646 /* check num args and type */
647 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
648 !ISPTR(a->n_left->n_type))
649 goto bad;
650
651 /* must first deal with argument size; use int size */
652 p = a->n_right;
653 if (p->n_type < INT) {
654 /* round up to word */
655 sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
656 }
657
658 p = buildtree(ADDROF, p, NIL); /* address of last arg */
659 p = optim(buildtree(PLUS, p, bcon(sz)));
660 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
661 q = buildtree(CAST, q, p);
662 p = q->n_right;
663 nfree(q->n_left);
664 nfree(q);
665 p = buildtree(ASSIGN, a->n_left, p);
666 nfree(a);
667
668 return p;
669
670 bad:
671 uerror("bad argument to __builtin_stdarg_start");
672 return bcon(0);
673 }
674
675 NODE *
mips_builtin_va_arg(const struct bitable * bt,NODE * a)676 mips_builtin_va_arg(const struct bitable *bt, NODE *a)
677 {
678 NODE *p, *q, *r;
679 int sz, tmpnr;
680
681 /* check num args and type */
682 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
683 !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
684 goto bad;
685
686 r = a->n_right;
687
688 /* get type size */
689 sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
690 if (sz < SZINT/SZCHAR) {
691 werror("%s%s promoted to int when passed through ...",
692 r->n_type & 1 ? "unsigned " : "",
693 DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
694 sz = SZINT/SZCHAR;
695 }
696
697 /* alignment */
698 p = tcopy(a->n_left);
699 if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
700 p = buildtree(PLUS, p, bcon(7));
701 p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap);
702 }
703
704 /* create a copy to a temp node */
705 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
706 tmpnr = regno(q);
707 p = buildtree(ASSIGN, q, p);
708
709 q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
710 q = buildtree(PLUS, q, bcon(sz));
711 q = buildtree(ASSIGN, a->n_left, q);
712
713 q = buildtree(COMOP, p, q);
714
715 nfree(a->n_right);
716 nfree(a);
717
718 p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
719 p = buildtree(UMUL, p, NIL);
720 p = buildtree(COMOP, q, p);
721
722 return p;
723
724 bad:
725 uerror("bad argument to __builtin_va_arg");
726 return bcon(0);
727 }
728
729 NODE *
mips_builtin_va_end(const struct bitable * bt,NODE * a)730 mips_builtin_va_end(const struct bitable *bt, NODE *a)
731 {
732 tfree(a);
733 return bcon(0);
734 }
735
736 NODE *
mips_builtin_va_copy(const struct bitable * bt,NODE * a)737 mips_builtin_va_copy(const struct bitable *bt, NODE *a)
738 {
739 NODE *f;
740
741 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
742 goto bad;
743 f = buildtree(ASSIGN, a->n_left, a->n_right);
744 nfree(a);
745 return f;
746
747 bad:
748 uerror("bad argument to __buildtin_va_copy");
749 return bcon(0);
750 }
751
752 static int constructor;
753 static int destructor;
754
755 /*
756 * Give target the opportunity of handling pragmas.
757 */
758 int
mypragma(char * str)759 mypragma(char *str)
760 {
761
762 if (strcmp(str, "tls") == 0) {
763 uerror("thread-local storage not supported for this target");
764 return 1;
765 }
766 if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
767 constructor = 1;
768 return 1;
769 }
770 if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
771 destructor = 1;
772 return 1;
773 }
774
775 return 0;
776 }
777
778 /*
779 * Called when a identifier has been declared, to give target last word.
780 */
781 void
fixdef(struct symtab * sp)782 fixdef(struct symtab *sp)
783 {
784 if ((constructor || destructor) && (sp->sclass != PARAM)) {
785 printf("\t.section .%ctors,\"aw\",@progbits\n",
786 constructor ? 'c' : 'd');
787 printf("\t.p2align 2\n");
788 printf("\t.long %s\n", exname(sp->sname));
789 printf("\t.previous\n");
790 constructor = destructor = 0;
791 }
792 }
793
794 void
pass1_lastchance(struct interpass * ip)795 pass1_lastchance(struct interpass *ip)
796 {
797 }
798