1: // Copyright (C) 1984-1998 by Symantec
2: // Copyright (C) 2000-2011 by Digital Mars
3: // All Rights Reserved
4: // http://www.digitalmars.com
5: // Written by Walter Bright
6: /*
7: * This source file is made available for personal use
8: * only. The license is in /dmd/src/dmd/backendlicense.txt
9: * or /dm/src/dmd/backendlicense.txt
10: * For any other uses, please contact Digital Mars.
11: */
12:
13:
14: #if !SPP
15:
16: #include <stdio.h>
17: #include <string.h>
18: #include <time.h>
19:
20: #include "cc.h"
21: #include "oper.h"
22: #include "global.h"
23: #include "type.h"
24: #include "filespec.h"
25: #include "code.h"
26: #include "cgcv.h"
27: #include "go.h"
28: #include "dt.h"
29: #if SCPP
30: #include "parser.h"
31: #include "cpp.h"
32: #include "el.h"
33: #endif
34:
35: static char __file__[] = __FILE__; /* for tassert.h */
36: #include "tassert.h"
37:
38: static int addrparam; /* see if any parameters get their address taken */
39:
40: /**********************************
41: * We put out an external definition.
42: */
43:
44: #if SCPP
45:
46: void out_extdef(symbol *s)
47: {
48: pstate.STflags |= PFLextdef;
49: if (//config.flags2 & CFG2phgen ||
50: (config.flags2 & (CFG2phauto | CFG2phautoy) &&
51: !(pstate.STflags & (PFLhxwrote | PFLhxdone)))
52: )
53:
54: synerr(EM_data_in_pch,prettyident(s)); // data or code in precompiled header
55: }
56:
57: #endif
58:
59: #if TX86
60: #if SCPP
61: /********************************
62: * Put out code segment name record.
63: */
64:
65: void outcsegname(char *csegname)
66: {
67: obj_codeseg(csegname,0);
68: }
69: #endif
70: #endif
71:
72: /***********************************
73: * Output function thunk.
74: */
75:
76: #if SCPP
77:
78: void outthunk(symbol *sthunk,symbol *sfunc,unsigned p,tym_t thisty,
79: targ_size_t d,int i,targ_size_t d2)
80: {
81: cod3_thunk(sthunk,sfunc,p,thisty,d,i,d2);
82: sthunk->Sfunc->Fflags &= ~Fpending;
83: sthunk->Sfunc->Fflags |= Foutput; /* mark it as having been output */
84: }
85:
86: #endif
87:
88: /***************************
89: * Write out statically allocated data.
90: * Input:
91: * s symbol to be initialized
92: */
93:
94: #if TX86
95:
96: void outdata(symbol *s)
97: {
98: #if HTOD
99: return;
100: #endif
101: dt_t *dtstart,*dt;
102: targ_size_t datasize,a;
103: int seg;
104: targ_size_t offset;
105: int flags;
106: tym_t ty;
107:
108: symbol_debug(s);
109: #ifdef DEBUG
110: debugy && dbg_printf("outdata('%s')\n",s->Sident);
111: #endif
112: //printf("outdata('%s', ty=x%x)\n",s->Sident,s->Stype->Tty);
113: //symbol_print(s);
114:
115: // Data segment variables are always live on exit from a function
116: s->Sflags |= SFLlivexit;
117:
118: dtstart = s->Sdt;
119: s->Sdt = NULL; // it will be free'd
120: #if OMFOBJ
121: int tls = 0;
122: #endif
123: #if SCPP && TARGET_WINDOS
124: if (eecontext.EEcompile)
125: { s->Sfl = (s->ty() & mTYfar) ? FLfardata : FLextern;
126: s->Sseg = UNKNOWN;
127: goto Lret; // don't output any data
128: }
129: #endif
130: datasize = 0;
131: ty = s->ty();
132: if (ty & mTYexport && config.wflags & WFexpdef && s->Sclass != SCstatic)
133: obj_export(s,0); // export data definition
134: for (dt = dtstart; dt; dt = dt->DTnext)
135: {
136: //printf("dt = %p, dt = %d\n",dt,dt->dt);
137: switch (dt->dt)
138: { case DT_abytes:
139: { // Put out the data for the string, and
140: // reserve a spot for a pointer to that string
141: #if ELFOBJ || MACHOBJ
142: datasize += size(dt->Dty);
143: dt->DTabytes += elf_data_cdata(dt->DTpbytes,dt->DTnbytes,&dt->DTseg);
144: #else
145: targ_size_t *poffset;
146: datasize += size(dt->Dty);
147: if (tybasic(dt->Dty) == TYcptr)
148: { seg = cseg;
149: poffset = &Coffset;
150: }
151: #if SCPP
152: else if (tybasic(dt->Dty) == TYfptr &&
153: dt->DTnbytes > config.threshold)
154: {
155: seg = obj_fardata(s->Sident,dt->DTnbytes,&offset);
156: poffset = &offset;
157: }
158: #endif
159: else
160: { seg = DATA;
161: poffset = &Doffset;
162: }
163: dt->DTseg = seg;
164: dt->DTabytes += *poffset;
165: obj_bytes(seg,*poffset,dt->DTnbytes,dt->DTpbytes);
166: *poffset += dt->DTnbytes;
167: #endif
168: break;
169: }
170: case DT_ibytes:
171: datasize += dt->DTn;
172: break;
173: case DT_nbytes:
174: //printf("DT_nbytes %d\n", dt->DTnbytes);
175: datasize += dt->DTnbytes;
176: break;
177: case DT_symsize:
178: #if MARS
179: assert(0);
180: #else
181: dt->DTazeros = type_size(s->Stype);
182: #endif
183: goto case_azeros;
184: case DT_azeros:
185: /* A block of zeros
186: */
187: //printf("DT_azeros %d\n", dt->DTazeros);
188: case_azeros:
189: datasize += dt->DTazeros;
190: if (dt == dtstart && !dt->DTnext && s->Sclass != SCcomdat)
191: { /* first and only, so put in BSS segment
192: */
193: switch (ty & mTYLINK)
194: {
195: #if OMFOBJ
196: case mTYfar: // if far data
197: seg = obj_fardata(s->Sident,datasize,&s->Soffset);
198: s->Sfl = FLfardata;
199: break;
200: #endif
201: case mTYcs:
202: #if OMFOBJ
203: seg = cseg;
204: #endif
205: Coffset = align(datasize,Coffset);
206: s->Soffset = Coffset;
207: Coffset += datasize;
208: s->Sfl = FLcsdata;
209: break;
210: case mTYthread:
211: { seg_data *pseg = obj_tlsseg_bss();
212: #if ELFOBJ || MACHOBJ
213: s->Sseg = pseg->SDseg;
214: elf_data_start(s, datasize, pseg->SDseg);
215: obj_lidata(pseg->SDseg, pseg->SDoffset, datasize);
216: #else
217: targ_size_t TDoffset = pseg->SDoffset;
218: TDoffset = align(datasize,TDoffset);
219: s->Soffset = TDoffset;
220: TDoffset += datasize;
221: pseg->SDoffset = TDoffset;
222: seg = pseg->SDseg;
223: tls = 1;
224: #endif
225: s->Sfl = FLtlsdata;
226: break;
227: }
228: default:
229: #if ELFOBJ || MACHOBJ
230: elf_data_start(s,datasize,UDATA);
231: obj_lidata(s->Sseg,s->Soffset,datasize);
232: #else
233: seg = UDATA;
234: UDoffset = align(datasize,UDoffset);
235: s->Soffset = UDoffset;
236: UDoffset += datasize;
237: #endif
238: s->Sfl = FLudata; // uninitialized data
239: break;
240: }
241: #if ELFOBJ || MACHOBJ
242: assert(s->Sseg != UNKNOWN);
243: if (s->Sclass == SCglobal || s->Sclass == SCstatic)
244: objpubdef(s->Sseg,s,s->Soffset); /* do the definition */
245: /* if a pubdef to be done */
246: #else
247: s->Sseg = seg;
248: if (s->Sclass == SCglobal) /* if a pubdef to be done */
249: objpubdef(seg,s,s->Soffset); /* do the definition */
250: #endif
251: searchfixlist(s);
252: if (config.fulltypes &&
253: !(s->Sclass == SCstatic && funcsym_p)) // not local static
254: cv_outsym(s);
255: #if SCPP
256: out_extdef(s);
257: #endif
258: goto Lret;
259: }
260: break;
261: case DT_common:
262: assert(!dt->DTnext);
263: outcommon(s,dt->DTazeros);
264: goto Lret;
265:
266: case DT_xoff:
267: { symbol *sb = dt->DTsym;
268:
269: if (tyfunc(sb->ty()))
270: #if SCPP
271: nwc_mustwrite(sb);
272: #else
273: ;
274: #endif
275: else if (sb->Sdt) // if initializer for symbol
276: outdata(sb); // write out data for symbol
277: }
278: case DT_coff:
279: datasize += size(dt->Dty);
280: break;
281: case DT_1byte:
282: datasize++;
283: break;
284: default:
285: #ifdef DEBUG
286: dbg_printf("dt = %p, dt = %d\n",dt,dt->dt);
287: #endif
288: assert(0);
289: }
290: }
291:
292: if (s->Sclass == SCcomdat) // if initialized common block
293: {
294: seg = obj_comdat(s);
295: #if ELFOBJ || OMFOBJ
296: s->Soffset = 0;
297: #endif
298: switch (ty & mTYLINK)
299: {
300: #if OMFOBJ
301: case mTYfar: // if far data
302: s->Sfl = FLfardata;
303: break;
304: #endif
305: case mTYcs:
306: s->Sfl = FLcsdata;
307: break;
308: case mTYnear:
309: case 0:
310: s->Sfl = FLdata; // initialized data
311: break;
312: case mTYthread:
313: s->Sfl = FLtlsdata;
314: #if OMFOBJ
315: tls = 1;
316: #endif
317: break;
318:
319: default:
320: assert(0);
321: }
322: }
323: else
324: {
325: switch (ty & mTYLINK)
326: {
327: #if OMFOBJ
328: case mTYfar: // if far data
329: seg = obj_fardata(s->Sident,datasize,&s->Soffset);
330: s->Sfl = FLfardata;
331: break;
332: #endif
333: case mTYcs:
334: assert(OMFOBJ);
335: seg = cseg;
336: Coffset = align(datasize,Coffset);
337: s->Soffset = Coffset;
338: s->Sfl = FLcsdata;
339: break;
340: case mTYthread:
341: { seg_data *pseg = obj_tlsseg();
342: #if ELFOBJ || MACHOBJ
343: s->Sseg = pseg->SDseg;
344: elf_data_start(s, datasize, s->Sseg);
345: // s->Soffset = pseg->SDoffset;
346: #else
347: targ_size_t TDoffset = pseg->SDoffset;
348: TDoffset = align(datasize,TDoffset);
349: s->Soffset = TDoffset;
350: tls = 1;
351: #endif
352: seg = pseg->SDseg;
353: s->Sfl = FLtlsdata;
354: break;
355: }
356: case mTYnear:
357: case 0:
358: #if ELFOBJ || MACHOBJ
359: seg = elf_data_start(s,datasize,DATA);
360: #else
361: seg = DATA;
362: alignOffset(DATA, datasize);
363: s->Soffset = Doffset;
364: #endif
365: s->Sfl = FLdata; // initialized data
366: break;
367: default:
368: assert(0);
369: }
370: }
371: #if ELFOBJ || MACHOBJ
372: if (s->Sseg == UNKNOWN)
373: s->Sseg = seg;
374: else
375: seg = s->Sseg;
376: if (s->Sclass == SCglobal || s->Sclass == SCstatic)
377: {
378: objpubdef(s->Sseg,s,s->Soffset); // do the definition
379: }
380: #else
381: s->Sseg = seg;
382: if (s->Sclass == SCglobal) /* if a pubdef to be done */
383: objpubdef(seg,s,s->Soffset); /* do the definition */
384: #endif
385: if (config.fulltypes &&
386: !(s->Sclass == SCstatic && funcsym_p)) // not local static
387: cv_outsym(s);
388: searchfixlist(s);
389:
390: /* Go back through list, now that we know its size, and send out */
391: /* the data. */
392:
393: offset = s->Soffset;
394:
395: for (dt = dtstart; dt; dt = dt->DTnext)
396: {
397: switch (dt->dt)
398: { case DT_abytes:
399: if (tyreg(dt->Dty))
400: flags = CFoff;
401: else
402: flags = CFoff | CFseg;
403: if (I64)
404: flags |= CFoffset64;
405: if (tybasic(dt->Dty) == TYcptr)
406: reftocodseg(seg,offset,dt->DTabytes);
407: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
408: else
409: reftodatseg(seg,offset,dt->DTabytes,dt->DTseg,flags);
410: #else
411: else if (dt->DTseg == DATA)
412: reftodatseg(seg,offset,dt->DTabytes,DATA,flags);
413: else
414: reftofarseg(seg,offset,dt->DTabytes,dt->DTseg,flags);
415: #endif
416: offset += size(dt->Dty);
417: break;
418: case DT_ibytes:
419: obj_bytes(seg,offset,dt->DTn,dt->DTdata);
420: offset += dt->DTn;
421: break;
422: case DT_nbytes:
423: obj_bytes(seg,offset,dt->DTnbytes,dt->DTpbytes);
424: offset += dt->DTnbytes;
425: break;
426: case DT_azeros:
427: //printf("obj_lidata(seg = %d, offset = %d, azeros = %d)\n", seg, offset, dt->DTazeros);
428: obj_lidata(seg,offset,dt->DTazeros);
429: offset += dt->DTazeros;
430: break;
431: case DT_xoff:
432: {
433: symbol *sb = dt->DTsym; // get external symbol pointer
434: a = dt->DToffset; // offset from it
435: if (tyreg(dt->Dty))
436: flags = CFoff;
437: else
438: flags = CFoff | CFseg;
439: if (I64)
440: flags |= CFoffset64;
441: offset += reftoident(seg,offset,sb,a,flags);
442: break;
443: }
444: case DT_coff:
445: reftocodseg(seg,offset,dt->DToffset);
446: offset += intsize;
447: break;
448: case DT_1byte:
449: obj_byte(seg,offset++,dt->DTonebyte);
450: break;
451: default:
452: #ifdef DEBUG
453: dbg_printf("dt = %p, dt = %d\n",dt,dt->dt);
454: #endif
455: assert(0);
456: }
457: }
458: #if ELFOBJ || MACHOBJ
459: Offset(seg) = offset;
460: #elif OMFOBJ
461: if (seg == DATA)
462: Doffset = offset;
463: else if (seg == cseg)
464: Coffset = offset;
465: else if (tls && s->Sclass != SCcomdat)
466: {
467: obj_tlsseg()->SDoffset = offset;
468: }
469: #else
470: #error "obj format?"
471: #endif
472: #if SCPP
473: out_extdef(s);
474: #endif
475: Lret:
476: dt_free(dtstart);
477: }
478:
479:
480:
481: /******************************
482: * Output n bytes of a common block, n > 0.
483: */
484:
485: void outcommon(symbol *s,targ_size_t n)
486: {
487: //printf("outcommon('%s',%d)\n",s->Sident,n);
488: if (n != 0)
489: {
490: assert(s->Sclass == SCglobal);
491: if (s->ty() & mTYcs) // if store in code segment
492: {
493: /* COMDEFs not supported in code segment
494: * so put them out as initialized 0s
495: */
496: dtnzeros(&s->Sdt,n);
497: outdata(s);
498: #if SCPP
499: out_extdef(s);
500: #endif
501: }
502: else if (s->ty() & mTYthread) // if store in thread local segment
503: {
504: #if ELFOBJ
505: s->Sclass = SCcomdef;
506: obj_comdef(s, 0, n, 1);
507: #else
508: /* COMDEFs not supported in tls segment
509: * so put them out as COMDATs with initialized 0s
510: */
511: s->Sclass = SCcomdat;
512: dtnzeros(&s->Sdt,n);
513: outdata(s);
514: #if SCPP && OMFOBJ
515: out_extdef(s);
516: #endif
517: #endif
518: }
519: else
520: {
521: #if ELFOBJ || MACHOBJ
522: s->Sclass = SCcomdef;
523: obj_comdef(s, 0, n, 1);
524: #else
525: s->Sclass = SCcomdef;
526: s->Sxtrnnum = obj_comdef(s,(s->ty() & mTYfar) == 0,n,1);
527: s->Sseg = UNKNOWN;
528: if (s->ty() & mTYfar)
529: s->Sfl = FLfardata;
530: else
531: s->Sfl = FLextern;
532: pstate.STflags |= PFLcomdef;
533: #if SCPP
534: ph_comdef(s); // notify PH that a COMDEF went out
535: #endif
536: #endif
537: }
538: if (config.fulltypes)
539: cv_outsym(s);
540: }
541: }
542: #endif // TX86
543:
544: /******************************
545: * Walk expression tree, converting it from a PARSER tree to
546: * a code generator tree.
547: */
548:
549: STATIC void outelem(elem *e)
550: {
551: symbol *s;
552: tym_t tym;
553: elem *e1;
554: #if SCPP
555: type *t;
556: #endif
557:
558: again:
559: assert(e);
560: elem_debug(e);
561:
562: #ifdef DEBUG
563: if (EBIN(e))
564: assert(e->E1 && e->E2);
565: // else if (EUNA(e))
566: // assert(e->E1 && !e->E2);
567: #endif
568:
569: #if SCPP
570: t = e->ET;
571: assert(t);
572: type_debug(t);
573: tym = t->Tty;
574: switch (tybasic(tym))
575: { case TYstruct:
576: t->Tcount++;
577: break;
578:
579: case TYarray:
580: t->Tcount++;
581: break;
582:
583: case TYbool:
584: case TYwchar_t:
585: case TYchar16:
586: case TYmemptr:
587: case TYvtshape:
588: case TYnullptr:
589: tym = tym_conv(t);
590: e->ET = NULL;
591: break;
592:
593: case TYenum:
594: tym = tym_conv(t->Tnext);
595: e->ET = NULL;
596: break;
597:
598: default:
599: e->ET = NULL;
600: break;
601: }
602: e->Nflags = 0;
603: e->Ety = tym;
604: #endif
605:
606: switch (e->Eoper)
607: {
608: default:
609: Lop:
610: #if DEBUG
611: //if (!EOP(e)) dbg_printf("e->Eoper = x%x\n",e->Eoper);
612: #endif
613: if (EBIN(e))
warning C6385: Invalid data: accessing 'unsigned char const * const optab1', the readable size is '183' bytes, but '1022' bytes might be read: Lines: 551, 552, 553, 558, 559, 606, 608, 609, 613
614: { outelem(e->E1);
615: e = e->E2;
616: }
617: else if (EUNA(e))
618: {
619: e = e->E1;
620: }
621: else
622: break;
623: #if SCPP
624: type_free(t);
625: #endif
626: goto again; /* iterate instead of recurse */
627: case OPaddr:
628: e1 = e->E1;
629: if (e1->Eoper == OPvar)
630: { // Fold into an OPrelconst
631: #if SCPP
632: el_copy(e,e1);
633: e->ET = t;
634: #else
635: tym = e->Ety;
636: el_copy(e,e1);
637: e->Ety = tym;
638: #endif
639: e->Eoper = OPrelconst;
640: el_free(e1);
641: goto again;
642: }
643: goto Lop;
644:
645: case OPrelconst:
646: case OPvar:
647: L6:
warning C4102: 'L6' : unreferenced label
648: s = e->EV.sp.Vsym;
649: assert(s);
650: symbol_debug(s);
651: switch (s->Sclass)
652: {
653: case SCregpar:
654: case SCparameter:
655: if (e->Eoper == OPrelconst)
656: addrparam = TRUE; // taking addr of param list
657: break;
658:
659: case SCstatic:
660: case SClocstat:
661: case SCextern:
662: case SCglobal:
663: case SCcomdat:
664: case SCcomdef:
665: #if PSEUDO_REGS
666: case SCpseudo:
667: #endif
668: case SCinline:
669: case SCsinline:
670: case SCeinline:
671: s->Sflags |= SFLlivexit;
672: /* FALL-THROUGH */
673: case SCauto:
674: case SCregister:
675: case SCfastpar:
676: case SCbprel:
677: case SCtmp:
678: if (e->Eoper == OPrelconst)
679: {
680: s->Sflags &= ~(SFLunambig | GTregcand);
681: }
682: #if SCPP && TX86 && OMFOBJ
683: else if (s->ty() & mTYfar)
684: e->Ety |= mTYfar;
685: #endif
686: break;
687: #if SCPP
688: case SCmember:
689: err_noinstance(s->Sscope,s);
690: goto L5;
691: case SCstruct:
692: cpperr(EM_no_instance,s->Sident); // no instance of class
693: L5:
694: e->Eoper = OPconst;
695: e->Ety = TYint;
696: return;
697:
698: case SCfuncalias:
699: e->EV.sp.Vsym = s->Sfunc->Falias;
700: goto L6;
701: case SCstack:
702: break;
703: case SCfunctempl:
704: cpperr(EM_no_template_instance, s->Sident);
705: break;
706: default:
707: #ifdef DEBUG
708: symbol_print(s);
709: WRclass((enum SC) s->Sclass);
710: #endif
711: assert(0);
712: #endif
713: }
714: #if SCPP
715: if (tyfunc(s->ty()))
716: {
717: #if SCPP
718: nwc_mustwrite(s); /* must write out function */
719: #else
720: ;
721: #endif
722: }
723: else if (s->Sdt) /* if initializer for symbol */
724: outdata(s); // write out data for symbol
725: #if ELFOBJ || MACHOBJ
726: if (config.flags3 & CFG3pic)
727: {
728: elfobj_gotref(s);
729: }
730: #endif
731: #endif
732: break;
733: case OPstring:
734: case OPconst:
735: case OPstrthis:
736: break;
737: case OPsizeof:
738: #if SCPP
739: e->Eoper = OPconst;
740: e->EV.Vlong = type_size(e->EV.sp.Vsym->Stype);
741: #else
742: assert(0);
743: #endif
744: break;
745:
746: #if SCPP
747: case OPstreq:
748: case OPstrpar:
749: case OPstrctor:
750: type_size(e->E1->ET);
751: goto Lop;
752:
753: case OPasm:
754: break;
755:
756: case OPctor:
757: nwc_mustwrite(e->EV.eop.Edtor);
758: case OPdtor:
759: // Don't put 'this' pointers in registers if we need
760: // them for EH stack cleanup.
761: e1 = e->E1;
762: elem_debug(e1);
763: if (e1->Eoper == OPadd)
764: e1 = e1->E1;
765: if (e1->Eoper == OPvar)
766: e1->EV.sp.Vsym->Sflags &= ~GTregcand;
767: goto Lop;
768: case OPmark:
769: break;
770: #endif
771: }
772: #if SCPP
773: type_free(t);
774: #endif
775: }
776:
777: /*************************************
778: * Determine register candidates.
779: */
780:
781: STATIC void out_regcand_walk(elem *e);
782:
783: void out_regcand(symtab_t *psymtab)
784: {
785: block *b;
786: SYMIDX si;
787: int ifunc;
788:
789: //printf("out_regcand()\n");
790: ifunc = (tybasic(funcsym_p->ty()) == TYifunc);
791: for (si = 0; si < psymtab->top; si++)
792: { symbol *s = psymtab->tab[si];
793:
794: symbol_debug(s);
795: //assert(sytab[s->Sclass] & SCSS); // only stack variables
796: s->Ssymnum = si; // Ssymnum trashed by cpp_inlineexpand
797: if (!(s->ty() & mTYvolatile) &&
798: #if TX86
799: !(ifunc && (s->Sclass == SCparameter || s->Sclass == SCregpar)) &&
800: #endif
801: s->Sclass != SCstatic)
802: s->Sflags |= (GTregcand | SFLunambig); // assume register candidate
803: else
804: s->Sflags &= ~(GTregcand | SFLunambig);
805: }
806:
807: addrparam = FALSE; // haven't taken addr of param yet
808: for (b = startblock; b; b = b->Bnext)
809: {
810: if (b->Belem)
811: out_regcand_walk(b->Belem);
812:
813: // Any assembler blocks make everything ambiguous
814: if (b->BC == BCasm)
815: for (si = 0; si < psymtab->top; si++)
816: psymtab->tab[si]->Sflags &= ~(SFLunambig | GTregcand);
817: }
818:
819: // If we took the address of one parameter, assume we took the
820: // address of all non-register parameters.
821: if (addrparam) // if took address of a parameter
822: {
823: for (si = 0; si < psymtab->top; si++)
824: if (psymtab->tab[si]->Sclass == SCparameter)
825: psymtab->tab[si]->Sflags &= ~(SFLunambig | GTregcand);
826: }
827:
828: }
829:
830: STATIC void out_regcand_walk(elem *e)
831: { symbol *s;
832:
833: while (1)
834: { elem_debug(e);
835:
836: if (EBIN(e))
837: { if (e->Eoper == OPstreq)
838: { if (e->E1->Eoper == OPvar)
839: { s = e->E1->EV.sp.Vsym;
840: s->Sflags &= ~(SFLunambig | GTregcand);
841: }
842: if (e->E2->Eoper == OPvar)
843: { s = e->E2->EV.sp.Vsym;
844: s->Sflags &= ~(SFLunambig | GTregcand);
845: }
846: }
847: out_regcand_walk(e->E1);
848: e = e->E2;
849: }
850: else if (EUNA(e))
851: {
852: // Don't put 'this' pointers in registers if we need
853: // them for EH stack cleanup.
854: if (e->Eoper == OPctor)
855: { elem *e1 = e->E1;
856:
857: if (e1->Eoper == OPadd)
858: e1 = e1->E1;
859: if (e1->Eoper == OPvar)
860: e1->EV.sp.Vsym->Sflags &= ~GTregcand;
861: }
862: e = e->E1;
863: }
864: else
865: { if (e->Eoper == OPrelconst)
866: {
867: s = e->EV.sp.Vsym;
868: assert(s);
869: symbol_debug(s);
870: switch (s->Sclass)
871: {
872: case SCregpar:
873: case SCparameter:
874: addrparam = TRUE; // taking addr of param list
875: break;
876: case SCauto:
877: case SCregister:
878: case SCtmp:
879: case SCfastpar:
880: case SCbprel:
881: s->Sflags &= ~(SFLunambig | GTregcand);
882: break;
883: }
884: }
885: else if (e->Eoper == OPvar)
886: {
887: if (e->EV.sp.Voffset)
888: { if (!(e->EV.sp.Voffset == 1 && tybyte(e->Ety)))
889: e->EV.sp.Vsym->Sflags &= ~GTregcand;
890: }
891: }
892: break;
893: }
894: }
895: }
896:
897: /**************************
898: * Optimize function,
899: * generate code for it,
900: * and write it out.
901: */
902:
903: STATIC void writefunc2(symbol *sfunc);
904:
905: void writefunc(symbol *sfunc)
906: {
907: #if HTOD
908: return;
909: #elif SCPP
910: writefunc2(sfunc);
911: #else
912: cstate.CSpsymtab = &globsym;
913: writefunc2(sfunc);
914: cstate.CSpsymtab = NULL;
915: #endif
916: }
917:
918: STATIC void writefunc2(symbol *sfunc)
919: {
920: block *b;
921: unsigned nsymbols;
922: SYMIDX si;
923: int anyasm;
924: #if OMFOBJ
925: int csegsave;
926: targ_size_t coffsetsave;
927: #endif
928: func_t *f = sfunc->Sfunc;
929: tym_t tyf;
930:
931: //printf("writefunc(%s)\n",sfunc->Sident);
932: debug(debugy && dbg_printf("writefunc(%s)\n",sfunc->Sident));
933: #if SCPP
934: if (CPP)
935: {
936:
937: // If constructor or destructor, make sure it has been fixed.
938: if (f->Fflags & (Fctor | Fdtor))
939: assert(errcnt || f->Fflags & Ffixed);
940:
941: // If this function is the 'trigger' to output the vtbl[], do so
942: if (f->Fflags3 & Fvtblgen && !eecontext.EEcompile)
943: { Classsym *stag;
944:
945: stag = (Classsym *) sfunc->Sscope;
946: {
947: enum SC scvtbl;
948:
949: scvtbl = (enum SC) ((config.flags2 & CFG2comdat) ? SCcomdat : SCglobal);
950: n2_genvtbl(stag,scvtbl,1);
951: #if VBTABLES
952: n2_genvbtbl(stag,scvtbl,1);
953: #endif
954: #if TX86 && OMFOBJ
955: if (config.fulltypes == CV4)
956: cv4_struct(stag,2);
957: #endif
958: }
959: }
960: }
961: #endif
962:
963: /* Signify that function has been output */
964: /* (before inline_do() to prevent infinite recursion!) */
965: f->Fflags &= ~Fpending;
966: f->Fflags |= Foutput;
967:
968: if (
969: #if SCPP
970: errcnt ||
971: #endif
972: (eecontext.EEcompile && eecontext.EEfunc != sfunc))
973: return;
974:
975: /* Copy local symbol table onto main one, making sure */
976: /* that the symbol numbers are adjusted accordingly */
977: //dbg_printf("f->Flocsym.top = %d\n",f->Flocsym.top);
978: nsymbols = f->Flocsym.top;
979: if (nsymbols > globsym.symmax)
warning C4018: '>' : signed/unsigned mismatch
980: { /* Reallocate globsym.tab[] */
981: globsym.symmax = nsymbols;
982: globsym.tab = symtab_realloc(globsym.tab, globsym.symmax);
983: }
984: debug(debugy && dbg_printf("appending symbols to symtab...\n"));
985: assert(globsym.top == 0);
986: memcpy(&globsym.tab[0],&f->Flocsym.tab[0],nsymbols * sizeof(symbol *));
987: globsym.top = nsymbols;
988:
989: assert(startblock == NULL);
990: if (f->Fflags & Finline) // if keep function around
991: { // Generate copy of function
992: block *bf;
993: block **pb;
994:
995: pb = &startblock;
996: for (bf = f->Fstartblock; bf; bf = bf->Bnext)
997: {
998: b = block_calloc();
999: *pb = b;
1000: pb = &b->Bnext;
1001:
1002: *b = *bf;
1003: assert(!b->Bsucc);
1004: assert(!b->Bpred);
1005: b->Belem = el_copytree(b->Belem);
1006: }
1007: }
1008: else
1009: { startblock = sfunc->Sfunc->Fstartblock;
1010: sfunc->Sfunc->Fstartblock = NULL;
1011: }
1012: assert(startblock);
1013:
1014: /* Do any in-line expansion of function calls inside sfunc */
1015: #if SCPP
1016: inline_do(sfunc);
1017: #endif
1018:
1019: #if SCPP
1020: /* If function is _STIxxxx, add in the auto destructors */
1021: #if NEWSTATICDTOR
1022: if (cpp_stidtors && memcmp("__SI",sfunc->Sident,4) == 0)
1023: #else
1024: if (cpp_stidtors && memcmp("_STI",sfunc->Sident,4) == 0)
1025: #endif
1026: { list_t el;
1027:
1028: assert(startblock->Bnext == NULL);
1029: el = cpp_stidtors;
1030: do
1031: {
1032: startblock->Belem = el_combine(startblock->Belem,list_elem(el));
1033: el = list_next(el);
1034: } while (el);
1035: list_free(&cpp_stidtors,FPNULL);
1036: }
1037: #endif
1038: assert(funcsym_p == NULL);
1039: funcsym_p = sfunc;
1040: tyf = tybasic(sfunc->ty());
1041:
1042: #if SCPP
1043: out_extdef(sfunc);
1044: #endif
1045:
1046: // TX86 computes parameter offsets in stackoffsets()
1047: //printf("globsym.top = %d\n", globsym.top);
1048: for (si = 0; si < globsym.top; si++)
1049: { symbol *s = globsym.tab[si];
1050:
1051: symbol_debug(s);
1052: //printf("symbol %d '%s'\n",si,s->Sident);
1053:
1054: type_size(s->Stype); // do any forward template instantiations
1055:
1056: s->Ssymnum = si; // Ssymnum trashed by cpp_inlineexpand
1057: s->Sflags &= ~(SFLunambig | GTregcand);
1058: switch (s->Sclass)
1059: {
1060: #if SCPP
1061: case SCfastpar:
1062: Lfp:
1063: s->Spreg = (tyf == TYmfunc) ? CX : AX;
1064: case SCauto:
1065: case SCregister:
1066: s->Sfl = FLauto;
1067: goto L3;
1068: case SCtmp:
1069: s->Sfl = FLtmp;
1070: goto L3;
1071: case SCbprel:
1072: s->Sfl = FLbprel;
1073: goto L3;
1074: case SCregpar:
1075: case SCparameter:
1076: if (tyf == TYjfunc && si == 0 &&
1077: type_jparam(s->Stype))
1078: { s->Sclass = SCfastpar; // put last parameter into register
1079: goto Lfp;
1080: }
1081: #else
1082: case SCfastpar:
1083: case SCauto:
1084: case SCregister:
1085: s->Sfl = FLauto;
1086: goto L3;
1087: case SCtmp:
1088: s->Sfl = FLtmp;
1089: goto L3;
1090: case SCbprel:
1091: s->Sfl = FLbprel;
1092: goto L3;
1093: case SCregpar:
1094: case SCparameter:
1095: #endif
1096: s->Sfl = FLpara;
1097: if (tyf == TYifunc)
1098: { s->Sflags |= SFLlivexit;
1099: break;
1100: }
1101: L3:
1102: if (!(s->ty() & mTYvolatile))
1103: s->Sflags |= GTregcand | SFLunambig; // assume register candidate */
1104: break;
1105: #if PSEUDO_REGS
1106: case SCpseudo:
1107: s->Sfl = FLpseudo;
1108: break;
1109: #endif
1110: case SCstatic:
1111: break; // already taken care of by datadef()
1112: case SCstack:
1113: s->Sfl = FLstack;
1114: break;
1115: default:
1116: #ifdef DEBUG
1117: symbol_print(s);
1118: #endif
1119: assert(0);
1120: }
1121: }
1122:
1123: addrparam = FALSE; // haven't taken addr of param yet
1124: anyasm = 0;
1125: numblks = 0;
1126: for (b = startblock; b; b = b->Bnext)
1127: {
1128: numblks++; // redo count
1129: memset(&b->_BLU,0,sizeof(b->_BLU));
1130: if (b->Belem)
1131: { outelem(b->Belem);
1132: #if SCPP
1133: if (el_noreturn(b->Belem) && !(config.flags3 & CFG3eh))
1134: { b->BC = BCexit;
1135: list_free(&b->Bsucc,FPNULL);
1136: }
1137: #endif
1138: #if MARS
1139: if (b->Belem->Eoper == OPhalt)
1140: { b->BC = BCexit;
1141: list_free(&b->Bsucc,FPNULL);
1142: }
1143: #endif
1144: }
1145: if (b->BC == BCasm)
1146: anyasm = 1;
1147: if (sfunc->Sflags & SFLexit && (b->BC == BCret || b->BC == BCretexp))
1148: { b->BC = BCexit;
1149: list_free(&b->Bsucc,FPNULL);
1150: }
1151: assert(b != b->Bnext);
1152: }
1153: PARSER = 0;
1154: if (eecontext.EEelem)
1155: { unsigned marksi = globsym.top;
1156:
1157: eecontext.EEin++;
1158: outelem(eecontext.EEelem);
1159: eecontext.EEelem = doptelem(eecontext.EEelem,TRUE);
1160: eecontext.EEin--;
1161: eecontext_convs(marksi);
1162: }
1163: maxblks = 3 * numblks; // allow for increase in # of blocks
1164: // If we took the address of one parameter, assume we took the
1165: // address of all non-register parameters.
1166: if (addrparam | anyasm) // if took address of a parameter
1167: {
1168: for (si = 0; si < globsym.top; si++)
1169: if (anyasm || globsym.tab[si]->Sclass == SCparameter)
1170: globsym.tab[si]->Sflags &= ~(SFLunambig | GTregcand);
1171: }
1172:
1173: block_pred(); // compute predecessors to blocks
1174: block_compbcount(); // eliminate unreachable blocks
1175: if (mfoptim)
1176: { OPTIMIZER = 1;
1177: optfunc(); /* optimize function */
1178: assert(dfo);
1179: OPTIMIZER = 0;
1180: }
1181: else
1182: {
1183: //dbg_printf("blockopt()\n");
1184: blockopt(0); /* optimize */
1185: }
1186:
1187: #if SCPP
1188: if (CPP)
1189: {
1190: // Look for any blocks that return nothing.
1191: // Do it after optimization to eliminate any spurious
1192: // messages like the implicit return on { while(1) { ... } }
1193: if (tybasic(funcsym_p->Stype->Tnext->Tty) != TYvoid &&
1194: !(funcsym_p->Sfunc->Fflags & (Fctor | Fdtor | Finvariant))
1195: #if DEBUG_XSYMGEN
1196: /* the internal dataview function is allowed to lie about its return value */
1197: && compile_state != kDataView
1198: #endif
1199: )
1200: { char err;
1201:
1202: err = 0;
1203: for (b = startblock; b; b = b->Bnext)
1204: { if (b->BC == BCasm) // no errors if any asm blocks
1205: err |= 2;
1206: else if (b->BC == BCret)
1207: err |= 1;
1208: }
1209: if (err == 1)
1210: func_noreturnvalue();
1211: }
1212: }
1213: #endif
1214: assert(funcsym_p == sfunc);
1215: if (eecontext.EEcompile != 1)
1216: {
1217: #if TX86
1218: if (symbol_iscomdat(sfunc))
1219: {
1220: #if OMFOBJ
1221: csegsave = cseg;
1222: coffsetsave = Coffset;
1223: #endif
1224: obj_comdat(sfunc);
1225: }
1226: else
1227: if (config.flags & CFGsegs) // if user set switch for this
1228: {
1229: #if SCPP || TARGET_WINDOS
1230: obj_codeseg(cpp_mangle(funcsym_p),1);
1231: #else
1232: obj_codeseg(funcsym_p->Sident, 1);
1233: #endif
1234: // generate new code segment
1235: }
1236: cod3_align(); // align start of function
1237: #if ELFOBJ || MACHOBJ
1238: elf_func_start(sfunc);
1239: #else
1240: sfunc->Sseg = cseg; // current code seg
1241: #endif
1242: #endif
1243: sfunc->Soffset = Coffset; // offset of start of function
1244: searchfixlist(sfunc); // backpatch any refs to this function
1245: }
1246:
1247: //dbg_printf("codgen()\n");
1248: #if SCPP
1249: if (!errcnt)
1250: #endif
1251: codgen(); // generate code
1252: //dbg_printf("after codgen for %s Coffset %x\n",sfunc->Sident,Coffset);
1253: blocklist_free(&startblock);
1254: #if SCPP
1255: PARSER = 1;
1256: #endif
1257: #if ELFOBJ || MACHOBJ
1258: elf_func_term(sfunc);
1259: #endif
1260: #if MARS
1261: /* This is to make uplevel references to SCfastpar variables
1262: * from nested functions work.
1263: */
1264: for (si = 0; si < globsym.top; si++)
1265: {
1266: Symbol *s = globsym.tab[si];
1267:
1268: switch (s->Sclass)
1269: { case SCfastpar:
1270: s->Sclass = SCauto;
1271: break;
1272: }
1273: }
1274: #endif
1275: if (eecontext.EEcompile == 1)
1276: goto Ldone;
1277: if (sfunc->Sclass == SCglobal)
1278: {
1279: #if OMFOBJ
1280: if (!(config.flags4 & CFG4allcomdat))
1281: objpubdef(cseg,sfunc,sfunc->Soffset); // make a public definition
1282: #endif
1283:
1284: #if SCPP && _WIN32
1285: char *id;
1286: // Determine which startup code to reference
1287: if (!CPP || !isclassmember(sfunc)) // if not member function
1288: { static char *startup[] =
1289: { "__acrtused","__acrtused_winc","__acrtused_dll",
1290: "__acrtused_con","__wacrtused","__wacrtused_con",
1291: };
1292: int i;
1293:
1294: id = sfunc->Sident;
1295: switch (id[0])
1296: {
1297: case 'D': if (strcmp(id,"DllMain"))
1298: break;
1299: if (config.exe == EX_NT)
1300: { i = 2;
1301: goto L2;
1302: }
1303: break;
1304:
1305: case 'm': if (strcmp(id,"main"))
1306: break;
1307: if (config.exe == EX_NT)
1308: i = 3;
1309: else if (config.wflags & WFwindows)
1310: i = 1;
1311: else
1312: i = 0;
1313: goto L2;
1314:
1315: case 'w': if (strcmp(id,"wmain") == 0)
1316: {
1317: if (config.exe == EX_NT)
1318: { i = 5;
1319: goto L2;
1320: }
1321: break;
1322: }
1323: case 'W': if (stricmp(id,"WinMain") == 0)
1324: {
1325: i = 0;
1326: goto L2;
1327: }
1328: if (stricmp(id,"wWinMain") == 0)
1329: {
1330: if (config.exe == EX_NT)
1331: { i = 4;
1332: goto L2;
1333: }
1334: }
1335: break;
1336:
1337: case 'L':
1338: case 'l': if (stricmp(id,"LibMain"))
1339: break;
1340: if (config.exe != EX_NT && config.wflags & WFwindows)
1341: { i = 2;
1342: goto L2;
1343: }
1344: break;
1345:
1346: L2: objextdef(startup[i]); // pull in startup code
1347: break;
1348: }
1349: }
1350: #endif
1351: }
1352: if (config.wflags & WFexpdef &&
1353: sfunc->Sclass != SCstatic &&
1354: sfunc->Sclass != SCsinline &&
1355: !(sfunc->Sclass == SCinline && !(config.flags2 & CFG2comdat)) &&
1356: sfunc->ty() & mTYexport)
1357: obj_export(sfunc,Poffset); // export function definition
1358:
1359: if (config.fulltypes)
1360: cv_func(sfunc); // debug info for function
1361:
1362: #if MARS
1363: /* After codgen() and writing debug info for the locals,
1364: * readjust the offsets of all stack variables so they
1365: * are relative to the frame pointer.
1366: * Necessary for nested function access to lexically enclosing frames.
1367: */
1368: cod3_adjSymOffsets();
1369: #endif
1370:
1371: #if OMFOBJ
1372: if (symbol_iscomdat(sfunc)) // if generated a COMDAT
1373: obj_setcodeseg(csegsave,coffsetsave); // reset to real code seg
1374: #endif
1375:
1376: /* Check if function is a constructor or destructor, by */
1377: /* seeing if the function name starts with _STI or _STD */
1378: {
1379: #if _M_I86
1380: short *p;
1381:
1382: p = (short *) sfunc->Sident;
1383: if (p[0] == 'S_' && (p[1] == 'IT' || p[1] == 'DT'))
1384: #else
1385: char *p;
1386:
1387: p = sfunc->Sident;
1388: if (p[0] == '_' && p[1] == 'S' && p[2] == 'T' &&
1389: (p[3] == 'I' || p[3] == 'D'))
1390: #endif
1391: obj_funcptr(sfunc);
1392: }
1393:
1394: Ldone:
1395: funcsym_p = NULL;
1396:
1397: #if SCPP
1398: // Free any added symbols
1399: freesymtab(globsym.tab,nsymbols,globsym.top);
1400: #endif
1401: globsym.top = 0;
1402:
1403: //dbg_printf("done with writefunc()\n");
1404: #if TX86
1405: util_free(dfo);
1406: #else
1407: MEM_PARF_FREE(dfo);
1408: #endif
1409: dfo = NULL;
1410: }
1411:
1412: /*************************
1413: * Align segment offset.
1414: * Input:
1415: * seg segment to be aligned
1416: * datasize size in bytes of object to be aligned
1417: */
1418:
1419: void alignOffset(int seg,targ_size_t datasize)
1420: {
1421: targ_size_t alignbytes;
1422:
1423: alignbytes = align(datasize,Offset(seg)) - Offset(seg);
1424: //dbg_printf("seg %d datasize = x%x, Offset(seg) = x%x, alignbytes = x%x\n",
1425: //seg,datasize,Offset(seg),alignbytes);
1426: if (alignbytes)
1427: obj_lidata(seg,Offset(seg),alignbytes);
1428: #if OMFOBJ
1429: Offset(seg) += alignbytes; /* offset of start of data */
1430: #endif
1431: }
1432:
1433:
1434: /***************************************
1435: * Write data into read-only data segment.
1436: * Return symbol for it.
1437: */
1438:
1439: #define ROMAX 32
1440: struct Readonly
1441: {
1442: symbol *sym;
1443: size_t length;
1444: unsigned char p[ROMAX];
1445: };
1446:
1447: #define RMAX 16
1448: static Readonly readonly[RMAX];
1449: static size_t readonly_length;
1450: static size_t readonly_i;
1451:
1452: void out_reset()
1453: {
1454: readonly_length = 0;
1455: readonly_i = 0;
1456: }
1457:
1458: symbol *out_readonly_sym(tym_t ty, void *p, int len)
1459: {
1460: #if 0
1461: printf("out_readonly_sym(ty = x%x)\n", ty);
1462: for (int i = 0; i < len; i++)
1463: printf(" [%d] = %02x\n", i, ((unsigned char*)p)[i]);
1464: #endif
1465: // Look for previous symbol we can reuse
1466: for (int i = 0; i < readonly_length; i++)
warning C4018: '<' : signed/unsigned mismatch
1467: {
1468: Readonly *r = &readonly[i];
1469: if (r->length == len && memcmp(p, r->p, len) == 0)
warning C6385: Invalid data: accessing 'argument 2', the readable size is '32' bytes, but '355' bytes might be read: Lines: 1466, 1468, 1469
1470: return r->sym;
1471: }
1472:
1473: symbol *s;
1474:
1475: #if ELFOBJ
1476: /* MACHOBJ can't go here, because the const data segment goes into
1477: * the _TEXT segment, and one cannot have a fixup from _TEXT to _TEXT.
1478: */
1479: s = elf_sym_cdata(ty, (char *)p, len);
1480: #else
1481: unsigned sz = tysize(ty);
1482:
1483: alignOffset(DATA, sz);
1484: s = symboldata(Doffset,ty | mTYconst);
1485: obj_write_bytes(SegData[DATA], len, p);
1486: //printf("s->Sseg = %d:x%x\n", s->Sseg, s->Soffset);
1487: #endif
1488: if (len <= ROMAX)
1489: { Readonly *r;
1490:
1491: if (readonly_length < RMAX)
1492: {
1493: r = &readonly[readonly_length];
1494: readonly_length++;
1495: }
1496: else
1497: { r = &readonly[readonly_i];
1498: readonly_i++;
1499: if (readonly_i >= RMAX)
1500: readonly_i = 0;
1501: }
1502: r->length = len;
1503: r->sym = s;
1504: memcpy(r->p, p, len);
1505: }
1506: return s;
1507: }
1508:
1509: void Srcpos::print(const char *func)
1510: {
1511: printf("%s(", func);
1512: #if MARS
1513: printf("Sfilename = %s", Sfilename ? Sfilename : "null");
1514: #else
1515: Sfile *sf = Sfilptr ? *Sfilptr : NULL;
1516: printf("Sfilptr = %p (filename = %s)", sf, sf ? sf->SFname : "null");
1517: #endif
1518: printf(", Slinnum = %u", Slinnum);
1519: #if SOURCE_OFFSETS
1520: printf(", Sfiloff = %d", Sfiloff);
1521: #endif
1522: printf(")\n");
1523: }
1524:
1525:
1526: #endif /* !SPP */
1527:
1528: