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