]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/8l/pass.c
merge
[plan9front.git] / sys / src / cmd / 8l / pass.c
1 #include        "l.h"
2
3 void
4 dodata(void)
5 {
6         int i;
7         Sym *s;
8         Prog *p;
9         long t, u;
10
11         if(debug['v'])
12                 Bprint(&bso, "%5.2f dodata\n", cputime());
13         Bflush(&bso);
14         for(p = datap; p != P; p = p->link) {
15                 s = p->from.sym;
16                 if(p->as == ADYNT || p->as == AINIT)
17                         s->value = dtype;
18                 if(s->type == SBSS)
19                         s->type = SDATA;
20                 if(s->type != SDATA)
21                         diag("initialize non-data (%d): %s\n%P",
22                                 s->type, s->name, p);
23                 t = p->from.offset + p->width;
24                 if(t > s->value)
25                         diag("initialize bounds (%ld): %s\n%P",
26                                 s->value, s->name, p);
27         }
28         /* allocate small guys */
29         datsize = 0;
30         for(i=0; i<NHASH; i++)
31         for(s = hash[i]; s != S; s = s->link) {
32                 if(s->type != SDATA)
33                 if(s->type != SBSS)
34                         continue;
35                 t = s->value;
36                 if(t == 0) {
37                         diag("%s: no size", s->name);
38                         t = 1;
39                 }
40                 t = rnd(t, 4);;
41                 s->value = t;
42                 if(t > MINSIZ)
43                         continue;
44                 s->value = datsize;
45                 datsize += t;
46                 s->type = SDATA1;
47         }
48
49         /* allocate the rest of the data */
50         for(i=0; i<NHASH; i++)
51         for(s = hash[i]; s != S; s = s->link) {
52                 if(s->type != SDATA) {
53                         if(s->type == SDATA1)
54                                 s->type = SDATA;
55                         continue;
56                 }
57                 t = s->value;
58                 s->value = datsize;
59                 datsize += t;
60         }
61
62         if(debug['j']) {
63                 /*
64                  * pad data with bss that fits up to next
65                  * 8k boundary, then push data to 8k
66                  */
67                 u = rnd(datsize, 8192);
68                 u -= datsize;
69                 for(i=0; i<NHASH; i++)
70                 for(s = hash[i]; s != S; s = s->link) {
71                         if(s->type != SBSS)
72                                 continue;
73                         t = s->value;
74                         if(t > u)
75                                 continue;
76                         u -= t;
77                         s->value = datsize;
78                         s->type = SDATA;
79                         datsize += t;
80                 }
81                 datsize += u;
82         }
83
84         /* now the bss */
85         bsssize = 0;
86         for(i=0; i<NHASH; i++)
87         for(s = hash[i]; s != S; s = s->link) {
88                 if(s->type != SBSS)
89                         continue;
90                 t = s->value;
91                 s->value = bsssize + datsize;
92                 bsssize += t;
93         }
94         xdefine("bdata", SDATA, 0L);
95         xdefine("edata", SBSS, datsize);
96         xdefine("end", SBSS, bsssize + datsize);
97         /* etext is defined in span.c */
98 }
99
100 Prog*
101 brchain(Prog *p)
102 {
103         int i;
104
105         for(i=0; i<20; i++) {
106                 if(p == P || p->as != AJMP)
107                         return p;
108                 p = p->pcond;
109         }
110         return P;
111 }
112
113 void
114 follow(void)
115 {
116
117         if(debug['v'])
118                 Bprint(&bso, "%5.2f follow\n", cputime());
119         Bflush(&bso);
120         firstp = prg();
121         lastp = firstp;
122         xfol(textp);
123         lastp->link = P;
124         firstp = firstp->link;
125 }
126
127 void
128 xfol(Prog *p)
129 {
130         Prog *q;
131         int i;
132         enum as a;
133
134 loop:
135         if(p == P)
136                 return;
137         if(p->as == ATEXT)
138                 curtext = p;
139         if(p->as == AJMP)
140         if((q = p->pcond) != P) {
141                 p->mark = 1;
142                 p = q;
143                 if(p->mark == 0)
144                         goto loop;
145         }
146         if(p->mark) {
147                 /* copy up to 4 instructions to avoid branch */
148                 for(i=0,q=p; i<4; i++,q=q->link) {
149                         if(q == P)
150                                 break;
151                         if(q == lastp)
152                                 break;
153                         a = q->as;
154                         if(a == ANOP) {
155                                 i--;
156                                 continue;
157                         }
158                         switch(a) {
159                         case AJMP:
160                         case ARET:
161                         case AIRETL:
162
163                         case APUSHL:
164                         case APUSHFL:
165                         case APUSHW:
166                         case APUSHFW:
167                         case APOPL:
168                         case APOPFL:
169                         case APOPW:
170                         case APOPFW:
171                                 goto brk;
172                         }
173                         if(q->pcond == P || q->pcond->mark)
174                                 continue;
175                         if(a == ACALL || a == ALOOP)
176                                 continue;
177                         for(;;) {
178                                 if(p->as == ANOP) {
179                                         p = p->link;
180                                         continue;
181                                 }
182                                 q = copyp(p);
183                                 p = p->link;
184                                 q->mark = 1;
185                                 lastp->link = q;
186                                 lastp = q;
187                                 if(q->as != a || q->pcond == P || q->pcond->mark)
188                                         continue;
189
190                                 q->as = relinv(q->as);
191                                 p = q->pcond;
192                                 q->pcond = q->link;
193                                 q->link = p;
194                                 xfol(q->link);
195                                 p = q->link;
196                                 if(p->mark)
197                                         return;
198                                 goto loop;
199                         }
200                 } /* */
201         brk:;
202                 q = prg();
203                 q->as = AJMP;
204                 q->line = p->line;
205                 q->to.type = D_BRANCH;
206                 q->to.offset = p->pc;
207                 q->pcond = p;
208                 p = q;
209         }
210         p->mark = 1;
211         lastp->link = p;
212         lastp = p;
213         a = p->as;
214         if(a == AJMP || a == ARET || a == AIRETL)
215                 return;
216         if(p->pcond != P)
217         if(a != ACALL) {
218                 q = brchain(p->link);
219                 if(q != P && q->mark)
220                 if(a != ALOOP) {
221                         p->as = relinv(a);
222                         p->link = p->pcond;
223                         p->pcond = q;
224                 }
225                 xfol(p->link);
226                 q = brchain(p->pcond);
227                 if(q->mark) {
228                         p->pcond = q;
229                         return;
230                 }
231                 p = q;
232                 goto loop;
233         }
234         p = p->link;
235         goto loop;
236 }
237
238 int
239 relinv(int a)
240 {
241
242         switch(a) {
243         case AJEQ:      return AJNE;
244         case AJNE:      return AJEQ;
245         case AJLE:      return AJGT;
246         case AJLS:      return AJHI;
247         case AJLT:      return AJGE;
248         case AJMI:      return AJPL;
249         case AJGE:      return AJLT;
250         case AJPL:      return AJMI;
251         case AJGT:      return AJLE;
252         case AJHI:      return AJLS;
253         case AJCS:      return AJCC;
254         case AJCC:      return AJCS;
255         case AJPS:      return AJPC;
256         case AJPC:      return AJPS;
257         case AJOS:      return AJOC;
258         case AJOC:      return AJOS;
259         }
260         diag("unknown relation: %s in %s", anames[a], TNAME);
261         return a;
262 }
263
264 void
265 doinit(void)
266 {
267         Sym *s;
268         Prog *p;
269         int x;
270
271         for(p = datap; p != P; p = p->link) {
272                 x = p->to.type;
273                 if(x != D_EXTERN && x != D_STATIC)
274                         continue;
275                 s = p->to.sym;
276                 if(s->type == 0 || s->type == SXREF)
277                         diag("undefined %s initializer of %s",
278                                 s->name, p->from.sym->name);
279                 p->to.offset += s->value;
280                 p->to.type = D_CONST;
281                 if(s->type == SDATA || s->type == SBSS)
282                         p->to.offset += INITDAT;
283         }
284 }
285
286 void
287 patch(void)
288 {
289         long c;
290         Prog *p, *q;
291         Sym *s;
292         long vexit;
293
294         if(debug['v'])
295                 Bprint(&bso, "%5.2f mkfwd\n", cputime());
296         Bflush(&bso);
297         mkfwd();
298         if(debug['v'])
299                 Bprint(&bso, "%5.2f patch\n", cputime());
300         Bflush(&bso);
301         s = lookup("exit", 0);
302         vexit = s->value;
303         for(p = firstp; p != P; p = p->link) {
304                 if(p->as == ATEXT)
305                         curtext = p;
306                 if(p->as == ACALL || p->as == ARET) {
307                         s = p->to.sym;
308                         if(s) {
309                                 if(debug['c'])
310                                         Bprint(&bso, "%s calls %s\n", TNAME, s->name);
311                                 switch(s->type) {
312                                 default:
313                                         /* diag prints TNAME first */
314                                         diag("undefined: %s", s->name);
315                                         s->type = STEXT;
316                                         s->value = vexit;
317                                         break;  /* or fall through to set offset? */
318                                 case STEXT:
319                                         p->to.offset = s->value;
320                                         break;
321                                 case SUNDEF:
322                                         p->pcond = UP;
323                                         p->to.offset = 0;
324                                         break;
325                                 }
326                                 p->to.type = D_BRANCH;
327                         }
328                 }
329                 if(p->to.type != D_BRANCH || p->pcond == UP)
330                         continue;
331                 c = p->to.offset;
332                 for(q = firstp; q != P;) {
333                         if(q->forwd != P)
334                         if(c >= q->forwd->pc) {
335                                 q = q->forwd;
336                                 continue;
337                         }
338                         if(c == q->pc)
339                                 break;
340                         q = q->link;
341                 }
342                 if(q == P) {
343                         diag("branch out of range in %s\n%P", TNAME, p);
344                         p->to.type = D_NONE;
345                 }
346                 p->pcond = q;
347         }
348
349         for(p = firstp; p != P; p = p->link) {
350                 if(p->as == ATEXT)
351                         curtext = p;
352                 p->mark = 0;    /* initialization for follow */
353                 if(p->pcond != P && p->pcond != UP) {
354                         p->pcond = brloop(p->pcond);
355                         if(p->pcond != P)
356                         if(p->to.type == D_BRANCH)
357                                 p->to.offset = p->pcond->pc;
358                 }
359         }
360 }
361
362 #define LOG     5
363 void
364 mkfwd(void)
365 {
366         Prog *p;
367         int i;
368         long dwn[LOG], cnt[LOG];
369         Prog *lst[LOG];
370
371         for(i=0; i<LOG; i++) {
372                 if(i == 0)
373                         cnt[i] = 1; else
374                         cnt[i] = LOG * cnt[i-1];
375                 dwn[i] = 1;
376                 lst[i] = P;
377         }
378         i = 0;
379         for(p = firstp; p != P; p = p->link) {
380                 if(p->as == ATEXT)
381                         curtext = p;
382                 i--;
383                 if(i < 0)
384                         i = LOG-1;
385                 p->forwd = P;
386                 dwn[i]--;
387                 if(dwn[i] <= 0) {
388                         dwn[i] = cnt[i];
389                         if(lst[i] != P)
390                                 lst[i]->forwd = p;
391                         lst[i] = p;
392                 }
393         }
394 }
395
396 Prog*
397 brloop(Prog *p)
398 {
399         int c;
400         Prog *q;
401
402         c = 0;
403         for(q = p; q != P; q = q->pcond) {
404                 if(q->as != AJMP)
405                         break;
406                 c++;
407                 if(c >= 5000)
408                         return P;
409         }
410         return q;
411 }
412
413 void
414 dostkoff(void)
415 {
416         Prog *p, *q;
417         long autoffset, deltasp;
418         int a, f, curframe, curbecome, maxbecome;
419
420         curframe = 0;
421         curbecome = 0;
422         maxbecome = 0;
423         curtext = 0;
424         for(p = firstp; p != P; p = p->link) {
425
426                 /* find out how much arg space is used in this TEXT */
427                 if(p->to.type == (D_INDIR+D_SP))
428                         if(p->to.offset > curframe)
429                                 curframe = p->to.offset;
430
431                 switch(p->as) {
432                 case ATEXT:
433                         if(curtext && curtext->from.sym) {
434                                 curtext->from.sym->frame = curframe;
435                                 curtext->from.sym->become = curbecome;
436                                 if(curbecome > maxbecome)
437                                         maxbecome = curbecome;
438                         }
439                         curframe = 0;
440                         curbecome = 0;
441
442                         curtext = p;
443                         break;
444
445                 case ARET:
446                         /* special form of RET is BECOME */
447                         if(p->from.type == D_CONST)
448                                 if(p->from.offset > curbecome)
449                                         curbecome = p->from.offset;
450                         break;
451                 }
452         }
453         if(curtext && curtext->from.sym) {
454                 curtext->from.sym->frame = curframe;
455                 curtext->from.sym->become = curbecome;
456                 if(curbecome > maxbecome)
457                         maxbecome = curbecome;
458         }
459
460         if(debug['b'])
461                 print("max become = %d\n", maxbecome);
462         xdefine("ALEFbecome", STEXT, maxbecome);
463
464         curtext = 0;
465         for(p = firstp; p != P; p = p->link) {
466                 switch(p->as) {
467                 case ATEXT:
468                         curtext = p;
469                         break;
470                 case ACALL:
471                         if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
472                                 f = maxbecome - curtext->from.sym->frame;
473                                 if(f <= 0)
474                                         break;
475                                 /* calling a become or calling a variable */
476                                 if(p->to.sym == S || p->to.sym->become) {
477                                         curtext->to.offset += f;
478                                         if(debug['b']) {
479                                                 curp = p;
480                                                 print("%D calling %D increase %d\n",
481                                                         &curtext->from, &p->to, f);
482                                         }
483                                 }
484                         }
485                         break;
486                 }
487         }
488
489         autoffset = 0;
490         deltasp = 0;
491         for(p = firstp; p != P; p = p->link) {
492                 if(p->as == ATEXT) {
493                         curtext = p;
494                         autoffset = p->to.offset;
495                         if(autoffset < 0) {
496                                 autoffset = 0;
497                                 p->to.offset = 0;
498                         }
499                         if(autoffset) {
500                                 p = appendp(p);
501                                 p->as = AADJSP;
502                                 p->from.type = D_CONST;
503                                 p->from.offset = autoffset;
504                         }
505                         deltasp = autoffset;
506                 }
507                 a = p->from.type;
508                 if(a == D_AUTO)
509                         p->from.offset += deltasp;
510                 if(a == D_PARAM)
511                         p->from.offset += deltasp + 4;
512                 a = p->to.type;
513                 if(a == D_AUTO)
514                         p->to.offset += deltasp;
515                 if(a == D_PARAM)
516                         p->to.offset += deltasp + 4;
517
518                 switch(p->as) {
519                 default:
520                         continue;
521                 case APUSHL:
522                 case APUSHFL:
523                         deltasp += 4;
524                         continue;
525                 case APUSHW:
526                 case APUSHFW:
527                         deltasp += 2;
528                         continue;
529                 case APOPL:
530                 case APOPFL:
531                         deltasp -= 4;
532                         continue;
533                 case APOPW:
534                 case APOPFW:
535                         deltasp -= 2;
536                         continue;
537                 case ARET:
538                         break;
539                 }
540
541                 if(autoffset != deltasp)
542                         diag("unbalanced PUSH/POP");
543                 if(p->from.type == D_CONST)
544                         goto become;
545
546                 if(autoffset) {
547                         q = p;
548                         p = appendp(p);
549                         p->as = ARET;
550
551                         q->as = AADJSP;
552                         q->from.type = D_CONST;
553                         q->from.offset = -autoffset;
554                 }
555                 continue;
556
557         become:
558                 q = p;
559                 p = appendp(p);
560                 p->as = AJMP;
561                 p->to = q->to;
562                 p->pcond = q->pcond;
563
564                 q->as = AADJSP;
565                 q->from = zprg.from;
566                 q->from.type = D_CONST;
567                 q->from.offset = -autoffset;
568                 q->to = zprg.to;
569                 continue;
570         }
571 }
572
573 long
574 atolwhex(char *s)
575 {
576         long n;
577         int f;
578
579         n = 0;
580         f = 0;
581         while(*s == ' ' || *s == '\t')
582                 s++;
583         if(*s == '-' || *s == '+') {
584                 if(*s++ == '-')
585                         f = 1;
586                 while(*s == ' ' || *s == '\t')
587                         s++;
588         }
589         if(s[0]=='0' && s[1]){
590                 if(s[1]=='x' || s[1]=='X'){
591                         s += 2;
592                         for(;;){
593                                 if(*s >= '0' && *s <= '9')
594                                         n = n*16 + *s++ - '0';
595                                 else if(*s >= 'a' && *s <= 'f')
596                                         n = n*16 + *s++ - 'a' + 10;
597                                 else if(*s >= 'A' && *s <= 'F')
598                                         n = n*16 + *s++ - 'A' + 10;
599                                 else
600                                         break;
601                         }
602                 } else
603                         while(*s >= '0' && *s <= '7')
604                                 n = n*8 + *s++ - '0';
605         } else
606                 while(*s >= '0' && *s <= '9')
607                         n = n*10 + *s++ - '0';
608         if(f)
609                 n = -n;
610         return n;
611 }
612
613 void
614 undef(void)
615 {
616         int i;
617         Sym *s;
618
619         for(i=0; i<NHASH; i++)
620         for(s = hash[i]; s != S; s = s->link)
621                 if(s->type == SXREF)
622                         diag("%s: not defined", s->name);
623 }
624
625 void
626 import(void)
627 {
628         int i;
629         Sym *s;
630
631         for(i = 0; i < NHASH; i++)
632                 for(s = hash[i]; s != S; s = s->link)
633                         if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
634                                 if(s->value != 0)
635                                         diag("value != 0 on SXREF");
636                                 undefsym(s);
637                                 if(debug['X'])
638                                         Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
639                                 if(debug['S'])
640                                         s->sig = 0;
641                         }
642 }
643
644 void
645 ckoff(Sym *s, long v)
646 {
647         if(v < 0 || v >= 1<<Roffset)
648                 diag("relocation offset %ld for %s out of range", v, s->name);
649 }
650
651 static Prog*
652 newdata(Sym *s, int o, int w, int t)
653 {
654         Prog *p;
655
656         p = prg();
657         if(edatap == P)
658                 datap = p;
659         else
660                 edatap->link = p;
661         edatap = p;
662         p->as = ADATA;
663         p->width = w;
664         p->from.scale = w;
665         p->from.type = t;
666         p->from.sym = s;
667         p->from.offset = o;
668         p->to.type = D_CONST;
669         return p;
670 }
671
672 void
673 export(void)
674 {
675         int i, j, n, off, nb, sv, ne;
676         Sym *s, *et, *str, **esyms;
677         Prog *p;
678         char buf[NSNAME], *t;
679
680         n = 0;
681         for(i = 0; i < NHASH; i++)
682                 for(s = hash[i]; s != S; s = s->link)
683                         if(s->type != SXREF && s->type != SUNDEF && (nexports == 0 && s->sig != 0 || s->subtype == SEXPORT || allexport))
684                                 n++;
685         esyms = malloc(n*sizeof(Sym*));
686         ne = n;
687         n = 0;
688         for(i = 0; i < NHASH; i++)
689                 for(s = hash[i]; s != S; s = s->link)
690                         if(s->type != SXREF && s->type != SUNDEF && (nexports == 0 && s->sig != 0 || s->subtype == SEXPORT || allexport))
691                                 esyms[n++] = s;
692         for(i = 0; i < ne-1; i++)
693                 for(j = i+1; j < ne; j++)
694                         if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
695                                 s = esyms[i];
696                                 esyms[i] = esyms[j];
697                                 esyms[j] = s;
698                         }
699
700         nb = 0;
701         off = 0;
702         et = lookup(EXPTAB, 0);
703         if(et->type != 0 && et->type != SXREF)
704                 diag("%s already defined", EXPTAB);
705         et->type = SDATA;
706         str = lookup(".string", 0);
707         if(str->type == 0)
708                 str->type = SDATA;
709         sv = str->value;
710         for(i = 0; i < ne; i++){
711                 s = esyms[i];
712                 if(debug['S'])
713                         s->sig = 0;
714                 /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
715
716                 /* signature */
717                 p = newdata(et, off, sizeof(long), D_EXTERN);
718                 off += sizeof(long);
719                 p->to.offset = s->sig;
720
721                 /* address */
722                 p = newdata(et, off, sizeof(long), D_EXTERN);
723                 off += sizeof(long);
724                 p->to.type = D_ADDR;
725                 p->to.index = D_EXTERN;
726                 p->to.sym = s;
727
728                 /* string */
729                 t = s->name;
730                 n = strlen(t)+1;
731                 for(;;){
732                         buf[nb++] = *t;
733                         sv++;
734                         if(nb >= NSNAME){
735                                 p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
736                                 p->to.type = D_SCONST;
737                                 memmove(p->to.scon, buf, NSNAME);
738                                 nb = 0;
739                         }
740                         if(*t++ == 0)
741                                 break;
742                 }
743
744                 /* name */
745                 p = newdata(et, off, sizeof(long), D_EXTERN);
746                 off += sizeof(long);
747                 p->to.type = D_ADDR;
748                 p->to.index = D_STATIC;
749                 p->to.sym = str;
750                 p->to.offset = sv-n;
751         }
752
753         if(nb > 0){
754                 p = newdata(str, sv-nb, nb, D_STATIC);
755                 p->to.type = D_SCONST;
756                 memmove(p->to.scon, buf, nb);
757         }
758
759         for(i = 0; i < 3; i++){
760                 newdata(et, off, sizeof(long), D_EXTERN);
761                 off += sizeof(long);
762         }
763         et->value = off;
764         if(sv == 0)
765                 sv = 1;
766         str->value = sv;
767         exports = ne;
768         free(esyms);
769 }