]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cc/pgen.c
awk: make empty FS unicodely-correct.
[plan9front.git] / sys / src / cmd / cc / pgen.c
1 #include "gc.h"
2
3 void
4 codgen(Node *n, Node *nn)
5 {
6         Prog *sp;
7         Node *n1, nod, nod1;
8
9         cursafe = 0;
10         curarg = 0;
11         maxargsafe = 0;
12         hasdoubled = 0;
13
14         /*
15          * isolate name
16          */
17         for(n1 = nn;; n1 = n1->left) {
18                 if(n1 == Z) {
19                         diag(nn, "cant find function name");
20                         return;
21                 }
22                 if(n1->op == ONAME)
23                         break;
24         }
25         nearln = nn->lineno;
26         gpseudo(ATEXT, n1->sym, nodconst(stkoff));
27         sp = p;
28
29         if(typecmplx[thisfn->link->etype]) {
30                 if(nodret == nil) {
31                         nodret = new(ONAME, Z, Z);
32                         nodret->sym = slookup(".ret");
33                         nodret->class = CPARAM;
34                         nodret->type = types[TIND];
35                         nodret->etype = TIND;
36                         nodret = new(OIND, nodret, Z);
37                 }
38                 n1 = nodret->left;
39                 if(n1->type == T || n1->type->link != thisfn->link) {
40                         n1->type = typ(TIND, thisfn->link);
41                         n1->etype = n1->type->etype;
42                         nodret = new(OIND, n1, Z);
43                         complex(nodret);
44                 }
45         }
46
47         /*
48          * isolate first argument
49          */
50         if(REGARG >= 0) {       
51                 if(typecmplx[thisfn->link->etype]) {
52                         nod1 = *nodret->left;
53                         nodreg(&nod, &nod1, REGARG);
54                         gmove(&nod, &nod1);
55                 } else
56                 if(firstarg && typeword[firstargtype->etype]) {
57                         nod1 = znode;
58                         nod1.op = ONAME;
59                         nod1.sym = firstarg;
60                         nod1.type = firstargtype;
61                         nod1.class = CPARAM;
62                         nod1.xoffset = align(0, firstargtype, Aarg1);
63                         nod1.etype = firstargtype->etype;
64                         xcom(&nod1);
65                         nodreg(&nod, &nod1, REGARG);
66                         gmove(&nod, &nod1);
67                 }
68         }
69
70         canreach = 1;
71         warnreach = 1;
72         gen(n);
73         if(canreach && thisfn->link->etype != TVOID){
74                 if(debug['B'])
75                         warn(Z, "no return at end of function: %s", n1->sym->name);
76                 else
77                         diag(Z, "no return at end of function: %s", n1->sym->name);
78         }
79         noretval(3);
80         gbranch(ORETURN);
81
82         if(!debug['N'] || debug['R'] || debug['P'])
83                 regopt(sp);
84         
85         if(thechar=='6' || thechar=='7' || thechar=='9' || hasdoubled)  /* [sic] */
86                 maxargsafe = round(maxargsafe, 8);
87         sp->to.offset += maxargsafe;
88 }
89
90 void
91 supgen(Node *n)
92 {
93         int owarn;
94         long spc;
95         Prog *sp;
96
97         if(n == Z)
98                 return;
99         suppress++;
100         owarn = warnreach;
101         warnreach = 0;
102         spc = pc;
103         sp = lastp;
104         gen(n);
105         lastp = sp;
106         pc = spc;
107         sp->link = nil;
108         suppress--;
109         warnreach = owarn;
110 }
111
112 Node*
113 uncomma(Node *n)
114 {
115         while(n != Z && n->op == OCOMMA) {
116                 cgen(n->left, Z);
117                 n = n->right;
118         }
119         return n;
120 }
121
122 void
123 gen(Node *n)
124 {
125         Node *l, nod, rn;
126         Prog *sp, *spc, *spb;
127         Case *cn;
128         long sbc, scc;
129         int snbreak, sncontin;
130         int f, o, oldreach;
131
132 loop:
133         if(n == Z)
134                 return;
135         nearln = n->lineno;
136         o = n->op;
137         if(debug['G'])
138                 if(o != OLIST)
139                         print("%L %O\n", nearln, o);
140
141         if(!canreach) {
142                 switch(o) {
143                 case OLABEL:
144                 case OCASE:
145                 case OLIST:
146                 case OCOMMA:
147                 case OBREAK:
148                 case OFOR:
149                 case OWHILE:
150                 case ODWHILE:
151                         /* all handled specially - see switch body below */
152                         break;
153                 default:
154                         if(warnreach) {
155                                 warn(n, "unreachable code %O", o);
156                                 warnreach = 0;
157                         }
158                 }
159         }
160
161         switch(o) {
162
163         default:
164                 complex(n);
165                 cgen(n, Z);
166                 break;
167
168         case OLIST:
169         case OCOMMA:
170                 gen(n->left);
171
172         rloop:
173                 n = n->right;
174                 goto loop;
175
176         case ORETURN:
177                 canreach = 0;
178                 warnreach = !suppress;
179                 complex(n);
180                 if(n->type == T)
181                         break;
182                 l = uncomma(n->left);
183                 if(l == Z) {
184                         noretval(3);
185                         gbranch(ORETURN);
186                         break;
187                 }
188                 if(typecmplx[n->type->etype]) {
189                         nod = znode;
190                         nod.op = OAS;
191                         nod.left = nodret;
192                         nod.right = l;
193                         nod.type = n->type;
194                         nod.complex = l->complex;
195                         cgen(&nod, Z);
196                         noretval(3);
197                         gbranch(ORETURN);
198                         break;
199                 }
200                 if(newvlongcode && !typefd[n->type->etype]){
201                         regret(&rn, n);
202                         regfree(&rn);
203                         nod = znode;
204                         nod.op = OAS;
205                         nod.left = &rn;
206                         nod.right = l;
207                         nod.type = n->type;
208                         nod.complex = l->complex;
209                         cgen(&nod, Z);
210                         noretval(2);
211                         gbranch(ORETURN);
212                         break;
213                 }
214                 regret(&nod, n);
215                 cgen(l, &nod);
216                 regfree(&nod);
217                 if(typefd[n->type->etype])
218                         noretval(1);
219                 else
220                         noretval(2);
221                 gbranch(ORETURN);
222                 break;
223
224         case OLABEL:
225                 canreach = 1;
226                 l = n->left;
227                 if(l) {
228                         l->pc = pc;
229                         if(l->label)
230                                 patch(l->label, pc);
231                 }
232                 gbranch(OGOTO); /* prevent self reference in reg */
233                 patch(p, pc);
234                 goto rloop;
235
236         case OGOTO:
237                 canreach = 0;
238                 warnreach = !suppress;
239                 n = n->left;
240                 if(n == Z)
241                         return;
242                 if(n->complex == 0) {
243                         diag(Z, "label undefined: %s", n->sym->name);
244                         return;
245                 }
246                 if(suppress)
247                         return;
248                 gbranch(OGOTO);
249                 if(n->pc) {
250                         patch(p, n->pc);
251                         return;
252                 }
253                 if(n->label)
254                         patch(n->label, pc-1);
255                 n->label = p;
256                 return;
257
258         case OCASE:
259                 canreach = 1;
260                 l = n->left;
261                 if(cases == C)
262                         diag(n, "case/default outside a switch");
263                 if(l == Z) {
264                         casf();
265                         cases->val = 0;
266                         cases->def = 1;
267                         cases->label = pc;
268                         cases->isv = 0;
269                         goto rloop;
270                 }
271                 complex(l);
272                 if(l->type == T)
273                         goto rloop;
274                 if(l->op != OCONST || !typeswitch[l->type->etype]) {
275                         diag(n, "case expression must be integer constant");
276                         goto rloop;
277                 }
278                 casf();
279                 cases->val = l->vconst;
280                 cases->def = 0;
281                 cases->label = pc;
282                 cases->isv = typev[l->type->etype];
283                 goto rloop;
284
285         case OSWITCH:
286                 l = n->left;
287                 complex(l);
288                 if(l->type == T)
289                         break;
290                 if(!typeswitch[l->type->etype]) {
291                         diag(n, "switch expression must be integer");
292                         break;
293                 }
294
295                 gbranch(OGOTO);         /* entry */
296                 sp = p;
297
298                 cn = cases;
299                 cases = C;
300                 casf();
301
302                 sbc = breakpc;
303                 breakpc = pc;
304                 snbreak = nbreak;
305                 nbreak = 0;
306                 gbranch(OGOTO);
307                 spb = p;
308
309                 gen(n->right);          /* body */
310                 if(canreach){
311                         gbranch(OGOTO);
312                         patch(p, breakpc);
313                         nbreak++;
314                 }
315
316                 patch(sp, pc);
317                 regalloc(&nod, l, Z);
318                 /* always signed */
319                 if(typev[l->type->etype])
320                         nod.type = types[TVLONG];
321                 else
322                         nod.type = types[TLONG];
323                 cgen(l, &nod);
324                 doswit(&nod);
325                 regfree(&nod);
326                 patch(spb, pc);
327
328                 cases = cn;
329                 breakpc = sbc;
330                 canreach = nbreak!=0;
331                 if(canreach == 0)
332                         warnreach = !suppress;
333                 nbreak = snbreak;
334                 break;
335
336         case OWHILE:
337         case ODWHILE:
338                 l = n->left;
339                 gbranch(OGOTO);         /* entry */
340                 sp = p;
341
342                 scc = continpc;
343                 continpc = pc;
344                 gbranch(OGOTO);
345                 spc = p;
346
347                 sbc = breakpc;
348                 breakpc = pc;
349                 snbreak = nbreak;
350                 nbreak = 0;
351                 gbranch(OGOTO);
352                 spb = p;
353
354                 patch(spc, pc);
355                 if(n->op == OWHILE)
356                         patch(sp, pc);
357                 bcomplex(l, Z);         /* test */
358                 patch(p, breakpc);
359                 if(l->op != OCONST || vconst(l) == 0)
360                         nbreak++;
361
362                 if(n->op == ODWHILE)
363                         patch(sp, pc);
364                 gen(n->right);          /* body */
365                 gbranch(OGOTO);
366                 patch(p, continpc);
367
368                 patch(spb, pc);
369                 continpc = scc;
370                 breakpc = sbc;
371                 canreach = nbreak!=0;
372                 if(canreach == 0)
373                         warnreach = !suppress;
374                 nbreak = snbreak;
375                 break;
376
377         case OFOR:
378                 l = n->left;
379                 if(!canreach && l->right->left && warnreach) {
380                         warn(n, "unreachable code FOR");
381                         warnreach = 0;
382                 }
383                 gen(l->right->left);    /* init */
384                 gbranch(OGOTO);         /* entry */
385                 sp = p;
386
387                 /* 
388                  * if there are no incoming labels in the 
389                  * body and the top's not reachable, warn
390                  */
391                 if(!canreach && warnreach && deadheads(n)) {
392                         warn(n, "unreachable code %O", o);
393                         warnreach = 0;
394                 }
395
396                 scc = continpc;
397                 continpc = pc;
398                 gbranch(OGOTO);
399                 spc = p;
400
401                 sbc = breakpc;
402                 breakpc = pc;
403                 snbreak = nbreak;
404                 nbreak = 0;
405                 sncontin = ncontin;
406                 ncontin = 0;
407                 gbranch(OGOTO);
408                 spb = p;
409
410                 patch(spc, pc);
411                 gen(l->right->right);   /* inc */
412                 patch(sp, pc);  
413                 if(l->left != Z) {      /* test */
414                         bcomplex(l->left, Z);
415                         patch(p, breakpc);
416                         if(l->left->op != OCONST || vconst(l->left) == 0)
417                                 nbreak++;
418                 }
419                 canreach = 1;
420                 gen(n->right);          /* body */
421                 if(canreach){
422                         gbranch(OGOTO);
423                         patch(p, continpc);
424                         ncontin++;
425                 }
426                 if(!ncontin && l->right->right && warnreach) {
427                         warn(l->right->right, "unreachable FOR inc");
428                         warnreach = 0;
429                 }
430
431                 patch(spb, pc);
432                 continpc = scc;
433                 breakpc = sbc;
434                 canreach = nbreak!=0;
435                 if(canreach == 0)
436                         warnreach = !suppress;
437                 nbreak = snbreak;
438                 ncontin = sncontin;
439                 break;
440
441         case OCONTINUE:
442                 if(continpc < 0) {
443                         diag(n, "continue not in a loop");
444                         break;
445                 }
446                 gbranch(OGOTO);
447                 patch(p, continpc);
448                 ncontin++;
449                 canreach = 0;
450                 warnreach = !suppress;
451                 break;
452
453         case OBREAK:
454                 if(breakpc < 0) {
455                         diag(n, "break not in a loop");
456                         break;
457                 }
458                 /*
459                  * Don't complain about unreachable break statements.
460                  * There are breaks hidden in yacc's output and some people
461                  * write return; break; in their switch statements out of habit.
462                  * However, don't confuse the analysis by inserting an 
463                  * unreachable reference to breakpc either.
464                  */
465                 if(!canreach)
466                         break;
467                 gbranch(OGOTO);
468                 patch(p, breakpc);
469                 nbreak++;
470                 canreach = 0;
471                 warnreach = !suppress;
472                 break;
473
474         case OIF:
475                 l = n->left;
476                 if(bcomplex(l, n->right)) {
477                         if(typefd[l->type->etype])
478                                 f = !l->fconst;
479                         else
480                                 f = !l->vconst;
481                         if(debug['c'])
482                                 print("%L const if %s\n", nearln, f ? "false" : "true");
483                         if(f) {
484                                 canreach = 1;
485                                 supgen(n->right->left);
486                                 oldreach = canreach;
487                                 canreach = 1;
488                                 gen(n->right->right);
489                                 /*
490                                  * treat constant ifs as regular ifs for 
491                                  * reachability warnings.
492                                  */
493                                 if(!canreach && oldreach && debug['w'] < 2)
494                                         warnreach = 0;
495                         }
496                         else {
497                                 canreach = 1;
498                                 gen(n->right->left);
499                                 oldreach = canreach;
500                                 canreach = 1;
501                                 supgen(n->right->right);
502                                 /*
503                                  * treat constant ifs as regular ifs for 
504                                  * reachability warnings.
505                                  */
506                                 if(!oldreach && canreach && debug['w'] < 2)
507                                         warnreach = 0;
508                                 canreach = oldreach;
509                         }
510                 }
511                 else {
512                         sp = p;
513                         canreach = 1;
514                         if(n->right->left != Z)
515                                 gen(n->right->left);
516                         oldreach = canreach;
517                         canreach = 1;
518                         if(n->right->right != Z) {
519                                 gbranch(OGOTO);
520                                 patch(sp, pc);
521                                 sp = p;
522                                 gen(n->right->right);
523                         }
524                         patch(sp, pc);
525                         canreach = canreach || oldreach;
526                         if(canreach == 0)
527                                 warnreach = !suppress;
528                 }
529                 break;
530
531         case OSET:
532         case OUSED:
533                 usedset(n->left, o);
534                 break;
535         }
536 }
537
538 void
539 usedset(Node *n, int o)
540 {
541         if(n->op == OLIST) {
542                 usedset(n->left, o);
543                 usedset(n->right, o);
544                 return;
545         }
546         complex(n);
547         switch(n->op) {
548         case OADDR:     /* volatile */
549                 gins(ANOP, n, Z);
550                 break;
551         case ONAME:
552                 if(o == OSET)
553                         gins(ANOP, Z, n);
554                 else
555                         gins(ANOP, n, Z);
556                 break;
557         }
558 }
559
560 int
561 bcomplex(Node *n, Node *c)
562 {
563         Node *b, nod;
564
565
566         complex(n);
567         if(n->type != T)
568         if(tcompat(n, T, n->type, tnot))
569                 n->type = T;
570         if(n->type == T) {
571                 gbranch(OGOTO);
572                 return 0;
573         }
574         if(c != Z && n->op == OCONST && deadheads(c))
575                 return 1;
576         /* this is not quite right yet, so ignore it for now */
577         if(0 && newvlongcode && typev[n->type->etype] && machcap(Z)) {
578                 b = &nod;
579                 b->op = ONE;
580                 b->left = n;
581                 b->right = new(0, Z, Z);
582                 *b->right = *nodconst(0);
583                 b->right->type = n->type;
584                 b->type = types[TLONG];
585                 cgen(b, Z);
586                 return 0;
587         }
588         bool64(n);
589         boolgen(n, 1, Z);
590         return 0;
591 }