]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/2c/cgen.c
merge
[plan9front.git] / sys / src / cmd / 2c / cgen.c
1 #include "gc.h"
2
3 void
4 cgen(Node *n, int result, Node *nn)
5 {
6         Node *l, *r, nod;
7         int lg, rg, xg, yg, g, o;
8         long v;
9         Prog *p1;
10
11         if(n == Z || n->type == T)
12                 return;
13         if(typesuv[n->type->etype]) {
14                 sugen(n, result, nn, n->type->width);
15                 return;
16         }
17         if(debug['g']) {
18                 if(result == D_TREE)
19                         prtree(nn, "result");
20                 else
21                         print("result = %R\n", result);
22                 prtree(n, "cgen");
23         }
24         l = n->left;
25         r = n->right;
26         o = n->op;
27         if(n->addable >= INDEXED) {
28                 if(result == D_NONE) {
29                         if(nn == Z)
30                                 switch(o) {
31                                 default:
32                                         nullwarn(Z, Z);
33                                         break;
34                                 case OINDEX:
35                                         nullwarn(l, r);
36                                         break;
37                                 }
38                         return;
39                 }
40                 gmove(n->type, nn->type, D_TREE, n, result, nn);
41                 return;
42         }
43
44         v = 0; /* set */
45         switch(o) {
46         default:
47                 diag(n, "unknown op in cgen: %O", o);
48                 break;
49
50         case OAS:
51                 if(l->op == OBIT)
52                         goto bitas;
53                 /*
54                  * recursive use of result
55                  */
56                 if(result == D_NONE)
57                 if(l->addable > INDEXED)
58                 if(l->complex < FNX) {
59                         cgen(r, D_TREE, l);
60                         break;
61                 }
62
63                 /*
64                  * function calls on both sides
65                  */
66                 if(l->complex >= FNX && r->complex >= FNX) {
67                         cgen(r, D_TOS, r);
68                         v = argoff;
69                         lg = regaddr(result);
70                         lcgen(l, lg, Z);
71                         lg |= I_INDIR;
72                         adjsp(v - argoff);
73                         gmove(r->type, l->type, D_TOS, r, lg, l);
74                         if(result != D_NONE)
75                                 gmove(l->type, nn->type, lg, l, result, nn);
76                         regfree(lg);
77                         break;
78                 }
79
80                 rg = D_TREE;
81                 lg = D_TREE;
82                 if(r->complex >= l->complex) {
83                         /*
84                          * right side before left
85                          */
86                         if(result != D_NONE) {
87                                 rg = regalloc(n->type, result);
88                                 cgen(r, rg, n);
89                         } else
90                         if(r->complex >= FNX || r->addable < INDEXED) {
91                                 rg = regalloc(r->type, result);
92                                 cgen(r, rg, r);
93                         }
94                         if(l->addable < INDEXED) {
95                                 lg = regaddr(lg);
96                                 lcgen(l, lg, Z);
97                                 lg |= I_INDIR;
98                         }
99                 } else {
100                         /*
101                          * left before right
102                          */
103                         if(l->complex >= FNX || l->addable < INDEXED) {
104                                 lg = regaddr(lg);
105                                 lcgen(l, lg, Z);
106                                 lg |= I_INDIR;
107                         }
108                         if(result != D_NONE) {
109                                 rg = regalloc(n->type, result);
110                                 cgen(r, rg, n);
111                         } else
112                         if(r->addable < INDEXED) {
113                                 rg = regalloc(r->type, result);
114                                 cgen(r, rg, r);
115                         }
116                 }
117                 if(result != D_NONE) {
118                         gmove(n->type, l->type, rg, r, lg, l);
119                         gmove(n->type, nn->type, rg, r, result, nn);
120                 } else
121                         gmove(r->type, l->type, rg, r, lg, l);
122                 regfree(lg);
123                 regfree(rg);
124                 break;
125
126         bitas:
127                 n = l->left;
128                 rg = regalloc(tfield, result);
129                 if(l->complex >= r->complex) {
130                         lg = regaddr(D_NONE);
131                         lcgen(n, lg, Z);
132                         lg |= I_INDIR;
133                         cgen(r, rg, r);
134                 } else {
135                         cgen(r, rg, r);
136                         lg = regaddr(D_NONE);
137                         lcgen(n, lg, Z);
138                         lg |= I_INDIR;
139                 }
140                 g = regalloc(n->type, D_NONE);
141                 gmove(l->type, l->type, lg, l, g, l);
142                 bitstore(l, rg, lg, g, result, nn);
143                 break;
144
145         case OBIT:
146                 if(result == D_NONE) {
147                         nullwarn(l, Z);
148                         break;
149                 }
150                 g = bitload(n, D_NONE, D_NONE, result, nn);
151                 gopcode(OAS, nn->type, g, n, result, nn);
152                 regfree(g);
153                 break;
154
155         case ODOT:
156                 sugen(l, D_TREE, nodrat, l->type->width);
157                 if(result != D_NONE) {
158                         warn(n, "non-interruptable temporary");
159                         nod = *nodrat;
160                         if(!r || r->op != OCONST) {
161                                 diag(n, "DOT and no offset");
162                                 break;
163                         }
164                         nod.xoffset += r->vconst;
165                         nod.type = n->type;
166                         cgen(&nod, result, nn);
167                 }
168                 break;
169
170         case OASLDIV:
171         case OASLMOD:
172         case OASDIV:
173         case OASMOD:
174                 if(l->op == OBIT)
175                         goto asbitop;
176                 if(typefd[n->type->etype])
177                         goto asbinop;
178                 rg = D_TREE;
179                 if(l->complex >= FNX || r->complex >= FNX) {
180                         rg = D_TOS;
181                         cgen(r, rg, r);
182                         v = argoff;
183                 } else
184                 if(r->addable < INDEXED) {
185                         rg = regalloc(n->type, D_NONE);
186                         cgen(r, rg, r);
187                 }
188                 lg = D_TREE;
189                 if(!simplv(l)) {
190                         lg = regaddr(D_NONE);
191                         lcgen(l, lg, Z);        /* destroys register optimization */
192                         lg |= I_INDIR;
193                 }
194                 g = regpair(result);
195                 gmove(l->type, n->type, lg, l, g, n);
196                 if(rg == D_TOS)
197                         adjsp(v - argoff);
198                 gopcode(o, n->type, rg, r, g, n);
199                 if(o == OASLMOD || o == OASMOD)
200                         gmove(n->type, l->type, g+1, n, lg, l);
201                 else
202                         gmove(n->type, l->type, g, n, lg, l);
203                 if(result != D_NONE)
204                 if(o == OASLMOD || o == OASMOD)
205                         gmove(n->type, nn->type, g+1, n, result, nn);
206                 else
207                         gmove(n->type, nn->type, g, n, result, nn);
208                 regfree(g);
209                 regfree(g+1);
210                 regfree(lg);
211                 regfree(rg);
212                 break;
213
214         case OASXOR:
215         case OASAND:
216         case OASOR:
217                 if(l->op == OBIT)
218                         goto asbitop;
219                 if(l->complex >= FNX ||
220                    l->addable < INDEXED ||
221                    result != D_NONE ||
222                    typefd[n->type->etype])
223                         goto asbinop;
224                 rg = D_TREE;
225                 if(r->op != OCONST) {
226                         rg = regalloc(n->type, D_NONE);
227                         cgen(r, rg, r);
228                 }
229                 gopcode(o, l->type, rg, r, D_TREE, l);
230                 regfree(rg);
231                 break;
232
233         case OASADD:
234         case OASSUB:
235                 if(l->op == OBIT ||
236                    l->complex >= FNX ||
237                    l->addable < INDEXED ||
238                    result != D_NONE ||
239                    typefd[n->type->etype])
240                         goto asbinop;
241                 v = vconst(r);
242                 if(v > 0 && v <= 8) {
243                         gopcode(o, n->type, D_TREE, r, D_TREE, l);
244                         break;
245                 }
246                 rg = regalloc(n->type, D_NONE);
247                 cgen(r, rg, r);
248                 gopcode(o, n->type, rg, r, D_TREE, l);
249                 regfree(rg);
250                 break;
251
252         case OASLSHR:
253         case OASASHR:
254         case OASASHL:
255                 if(l->op == OBIT ||
256                    l->complex >= FNX ||
257                    l->addable < INDEXED ||
258                    result != D_NONE ||
259                    typefd[n->type->etype])
260                         goto asbinop;
261                 rg = D_TREE;
262                 v = vconst(r);
263                 if(v <= 0 || v > 8) {
264                         rg = regalloc(n->type, D_NONE);
265                         cgen(r, rg, r);
266                 }
267                 lg = regalloc(n->type, D_NONE);
268                 cgen(l, lg, l);
269                 gopcode(o, n->type, rg, r, lg, l);
270                 gmove(n->type, n->type, lg, l, D_TREE, l);
271                 regfree(lg);
272                 regfree(rg);
273                 break;
274
275         case OASLMUL:
276         case OASMUL:
277         asbinop:
278                 if(l->op == OBIT)
279                         goto asbitop;
280                 rg = D_TREE;
281                 if(l->complex >= FNX || r->complex >= FNX) {
282                         rg = D_TOS;
283                         cgen(r, rg, r);
284                         v = argoff;
285                 } else
286                 if(r->addable < INDEXED) {
287                         rg = regalloc(n->type, D_NONE);
288                         cgen(r, rg, r);
289                 } else {
290                         if(o == OASLSHR || o == OASASHR || o == OASASHL) {
291                                 v = vconst(r);
292                                 if(v <= 0 || v > 8) {
293                                         rg = regalloc(n->type, D_NONE);
294                                         cgen(r, rg, r);
295                                 }
296                         }
297                 }
298                 lg = D_TREE;
299                 if(!simplv(l)) {
300                         lg = regaddr(D_NONE);
301                         lcgen(l, lg, Z);        /* destroys register optimization */
302                         lg |= I_INDIR;
303                 }
304                 g = regalloc(n->type, result);
305                 gmove(l->type, n->type, lg, l, g, n);
306                 if(rg == D_TOS)
307                         adjsp(v - argoff);
308                 if(o == OASXOR)
309                         if(rg == D_TREE) {
310                                 rg = regalloc(n->type, D_NONE);
311                                 cgen(r, rg, r);
312                         }
313                 if(o == OASXOR || o == OASLSHR || o == OASASHR || o == OASASHL)
314                         if(rg == D_TOS) {
315                                 rg = regalloc(n->type, D_NONE);
316                                 gmove(n->type, n->type, D_TOS, n, rg, n);
317                         }
318                 gopcode(o, n->type, rg, r, g, n);
319                 gmove(n->type, l->type, g, n, lg, l);
320                 if(result != D_NONE)
321                         gmove(n->type, nn->type, g, n, result, nn);
322                 regfree(g);
323                 regfree(lg);
324                 regfree(rg);
325                 break;
326
327         asbitop:
328                 rg = regaddr(D_NONE);
329                 lg = regalloc(tfield, D_NONE);
330                 if(l->complex >= r->complex) {
331                         g = bitload(l, lg, rg, result, nn);
332                         xg = regalloc(r->type, D_NONE);
333                         cgen(r, xg, nn);
334                 } else {
335                         xg = regalloc(r->type, D_NONE);
336                         cgen(r, xg, nn);
337                         g = bitload(l, lg, rg, result, nn);
338                 }
339
340                 if(!typefd[n->type->etype]) {
341                         if(o == OASLDIV || o == OASDIV) {
342                                 yg = regpair(result);
343                                 gmove(tfield, n->type, g, l, yg, n);
344                                 gopcode(o, n->type, xg, r, yg, n);
345                                 gmove(n->type, tfield, yg, n, g, l);
346                                 regfree(yg);
347                                 regfree(yg+1);
348
349                                 regfree(xg);
350                                 bitstore(l, g, rg, lg, D_NONE, nn);
351                                 break;
352                         }
353                         if(o == OASLMOD || o == OASMOD) {
354                                 yg = regpair(result);
355                                 gmove(tfield, n->type, g, l, yg, n);
356                                 gopcode(o, n->type, xg, r, yg, n);
357                                 gmove(n->type, tfield, yg+1, n, g, l);
358                                 regfree(yg);
359                                 regfree(yg+1);
360
361                                 regfree(xg);
362                                 bitstore(l, g, rg, lg, D_NONE, nn);
363                                 break;
364                         }
365                 }
366
367                 yg = regalloc(n->type, result);
368                 gmove(tfield, n->type, g, l, yg, n);
369                 gopcode(o, n->type, xg, r, yg, n);
370                 gmove(n->type, tfield, yg, n, g, l);
371                 regfree(yg);
372
373                 regfree(xg);
374                 bitstore(l, g, rg, lg, D_NONE, nn);
375                 break;
376
377         case OCAST:
378                 if(result == D_NONE) {
379                         cgen(l, D_NONE, Z);
380                         break;
381                 }
382                 lg = result;
383                 if(l->complex >= FNX)
384                         lg = regret(l->type);
385                 lg = eval(l, lg);
386                 if(nocast(l->type, n->type)) {
387                         gmove(n->type, nn->type, lg, l, result, nn);
388                         regfree(lg);
389                         break;
390                 }
391                 if(nocast(n->type, nn->type)) {
392                         gmove(l->type, n->type, lg, l, result, nn);
393                         regfree(lg);
394                         break;
395                 }
396                 rg = regalloc(n->type, result);
397                 gmove(l->type, n->type, lg, l, rg, n);
398                 gmove(n->type, nn->type, rg, n, result, nn);
399                 regfree(rg);
400                 regfree(lg);
401                 break;
402
403         case OCOND:
404                 doinc(l, PRE);
405                 boolgen(l, 1, D_NONE, Z, l);
406                 p1 = p;
407
408                 inargs++;
409                 doinc(r->left, PRE);
410                 cgen(r->left, result, nn);
411                 doinc(r->left, POST);
412                 gbranch(OGOTO);
413                 patch(p1, pc);
414                 p1 = p;
415
416                 doinc(r->right, PRE);
417                 cgen(r->right, result, nn);
418                 doinc(r->right, POST);
419                 patch(p1, pc);
420                 inargs--;
421                 break;
422
423         case OIND:
424                 if(result == D_NONE) {
425                         nullwarn(l, Z);
426                         break;
427                 }
428                 lg = nodalloc(types[TIND], result, &nod);
429                 nod.lineno = n->lineno;
430                 if(l->op == OADD) {
431                         if(l->left->op == OCONST) {
432                                 nod.xoffset += l->left->vconst;
433                                 l = l->right;
434                         } else
435                         if(l->right->op == OCONST) {
436                                 nod.xoffset += l->right->vconst;
437                                 l = l->left;
438                         }
439                 }
440                 cgen(l, lg, l);
441                 gmove(n->type, nn->type, D_TREE, &nod, result, nn);
442                 regfree(lg);
443                 break;
444
445         case OFUNC:
446                 v = argoff;
447                 inargs++;
448                 gargs(r);
449                 lg = D_TREE;
450                 if(l->addable < INDEXED) {
451                         lg = regaddr(result);
452                         lcgen(l, lg, Z);
453                         lg |= I_INDIR;
454                 }
455                 inargs--;
456                 doinc(r, POST);
457                 doinc(l, POST);
458                 gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
459                 regfree(lg);
460                 if(inargs)
461                         adjsp(v - argoff);
462                 if(result != D_NONE) {
463                         lg = regret(n->type);
464                         gmove(n->type, nn->type, lg, n, result, nn);
465                 }
466                 break;
467
468         case OLDIV:
469         case OLMOD:
470         case ODIV:
471         case OMOD:
472                 if(result == D_NONE) {
473                         nullwarn(l, r);
474                         break;
475                 }
476                 if(typefd[n->type->etype])
477                         goto binop;
478                 if(r->addable >= INDEXED && r->complex < FNX) {
479                         lg = regpair(result);
480                         cgen(l, lg, l);
481                         rg = D_TREE;
482                 } else {
483                         cgen(r, D_TOS, r);
484                         v = argoff;
485                         lg = regpair(result);
486                         cgen(l, lg, l);
487                         adjsp(v - argoff);
488                         rg = D_TOS;
489                 }
490                 gopcode(o, n->type, rg, r, lg, l);
491                 if(o == OMOD || o == OLMOD)
492                         gmove(l->type, nn->type, lg+1, l, result, nn);
493                 else
494                         gmove(l->type, nn->type, lg, l, result, nn);
495                 regfree(lg);
496                 regfree(lg+1);
497                 break;
498
499         case OMUL:
500         case OLMUL:
501                 if(l->op == OCONST)
502                         if(mulcon(r, l, result, nn))
503                                 break;
504                 if(r->op == OCONST)
505                         if(mulcon(l, r, result, nn))
506                                 break;
507                 if(debug['M'])
508                         print("%L multiply\n", n->lineno);
509                 goto binop;
510
511         case OAND:
512                 if(r->op == OCONST)
513                 if(typeil[n->type->etype])
514                 if(l->op == OCAST) {
515                         if(typec[l->left->type->etype])
516                         if(!(r->vconst & ~0xff)) {
517                                 l = l->left;
518                                 goto binop;
519                         }
520                         if(typeh[l->left->type->etype])
521                         if(!(r->vconst & ~0xffff)) {
522                                 l = l->left;
523                                 goto binop;
524                         }
525                 }
526                 goto binop;
527
528         case OADD:
529                 if(result == D_TOS)
530                 if(r->addable >= INDEXED)
531                 if(l->op == OCONST)
532                 if(typeil[l->type->etype]) {
533                         v = l->vconst;
534                         if(v > -32768 && v < 32768) {
535                                 rg = regaddr(D_NONE);
536                                 gmove(r->type, r->type, D_TREE, r, rg, r);
537                                 gopcode(OADDR, types[TSHORT], D_NONE, Z, rg, r);
538                                 p->to.offset = v;
539                                 p->to.type |= I_INDIR;
540                                 regfree(rg);
541                                 break;
542                         }
543                 }
544
545         case OSUB:
546                 if(result == D_TOS)
547                 if(l->addable >= INDEXED)
548                 if(r->op == OCONST)
549                 if(typeil[r->type->etype]) {
550                         v = r->vconst;
551                         if(v > -32768 && v < 32768) {
552                                 if(n->op == OSUB)
553                                         v = -v;
554                                 lg = regaddr(D_NONE);
555                                 gmove(l->type, l->type, D_TREE, l, lg, l);
556                                 gopcode(OADDR, types[TSHORT], D_NONE, Z, lg, l);
557                                 p->to.offset = v;
558                                 p->to.type |= I_INDIR;
559                                 regfree(lg);
560                                 break;
561                         }
562                 }
563                 goto binop;
564
565         case OOR:
566         case OXOR:
567         binop:
568                 if(result == D_NONE) {
569                         nullwarn(l, r);
570                         break;
571                 }
572                 if(l->complex >= FNX && r->complex >= FNX) {
573                         cgen(r, D_TOS, r);
574                         v = argoff;
575                         lg = regalloc(l->type, result);
576                         cgen(l, lg, l);
577                         adjsp(v - argoff);
578                         if(o == OXOR) {
579                                 rg = regalloc(r->type, D_NONE);
580                                 gmove(r->type, r->type, D_TOS, r, rg, r);
581                                 gopcode(o, n->type, rg, r, lg, l);
582                                 regfree(rg);
583                         } else
584                                 gopcode(o, n->type, D_TOS, r, lg, l);
585                         gmove(n->type, nn->type, lg, l, result, nn);
586                         regfree(lg);
587                         break;
588                 }
589                 if(l->complex >= r->complex) {
590                         if(l->op == OADDR && (o == OADD || o == OSUB))
591                                 lg = regaddr(result);
592                         else
593                                 lg = regalloc(l->type, result);
594                         cgen(l, lg, l);
595                         rg = eval(r, D_NONE);
596                 } else {
597                         rg = regalloc(r->type, D_NONE);
598                         cgen(r, rg, r);
599                         lg = regalloc(l->type, result);
600                         cgen(l, lg, l);
601                 }
602                 if(o == OXOR) {
603                         if(rg == D_TREE) {
604                                 rg = regalloc(r->type, D_NONE);
605                                 cgen(r, rg, r);
606                         }
607                         if(rg == D_TOS) {
608                                 rg = regalloc(r->type, D_NONE);
609                                 gmove(r->type, r->type, D_TOS, r, rg, r);
610                         }
611                 }
612                 gopcode(o, n->type, rg, r, lg, l);
613                 gmove(n->type, nn->type, lg, l, result, nn);
614                 regfree(lg);
615                 regfree(rg);
616                 break;
617
618         case OASHL:
619                 if(r->op == OCONST)
620                         if(shlcon(l, r, result, nn))
621                                 break;
622         case OLSHR:
623         case OASHR:
624                 if(result == D_NONE) {
625                         nullwarn(l, r);
626                         break;
627                 }
628
629                 if(l->complex >= FNX && r->complex >= FNX) {
630                         cgen(r, D_TOS, r);
631                         v = argoff;
632                         lg = regalloc(l->type, result);
633                         cgen(l, lg, l);
634                         adjsp(v - argoff);
635                         rg = regalloc(r->type, D_NONE);
636                         gopcode(OAS, r->type, D_TOS, r, rg, r);
637                         gopcode(n->op, n->type, rg, r, lg, l);
638                         gmove(n->type, nn->type, lg, l, result, nn);
639                         regfree(lg);
640                         regfree(rg);
641                         break;
642                 }
643                 if(l->complex >= r->complex) {
644                         lg = regalloc(l->type, result);
645                         cgen(l, lg, l);
646                         v = vconst(r);
647                         if(v <= 0 || v > 8) {
648                                 rg = regalloc(r->type, D_NONE);
649                                 cgen(r, rg, r);
650                         } else
651                                 rg = eval(r, D_NONE);
652                 } else {
653                         rg = regalloc(r->type, D_NONE);
654                         cgen(r, rg, r);
655                         lg = regalloc(l->type, result);
656                         cgen(l, lg, l);
657                 }
658                 gopcode(o, n->type, rg, r, lg, l);
659                 gmove(n->type, nn->type, lg, l, result, nn);
660                 regfree(lg);
661                 regfree(rg);
662                 break;
663
664         case ONEG:
665         case OCOM:
666                 if(result == D_NONE) {
667                         nullwarn(l, Z);
668                         break;
669                 }
670                 lg = regalloc(l->type, result);
671                 cgen(l, lg, l);
672                 gopcode(o, l->type, D_NONE, Z, lg, l);
673                 gmove(n->type, nn->type, lg, l, result, nn);
674                 regfree(lg);
675                 break;
676
677         case OADDR:
678                 if(result == D_NONE) {
679                         nullwarn(l, Z);
680                         break;
681                 }
682                 if(l->op == OINDEX && l->scale == 4 && result != D_TOS) {
683                         /* index scaled by 1, add is better */
684                         nod = *l;
685                         nod.op = OADD;
686                         nod.addable = 0;
687                         cgen(&nod, result, nn);
688                         break;
689                 }
690                 lcgen(l, result, nn);
691                 break;
692
693         case OEQ:
694         case ONE:
695         case OLE:
696         case OLT:
697         case OGE:
698         case OGT:
699         case OLO:
700         case OLS:
701         case OHI:
702         case OHS:
703                 if(result == D_NONE) {
704                         nullwarn(l, r);
705                         break;
706                 }
707                 boolgen(n, 1, result, nn, Z);
708                 break;
709
710         case OANDAND:
711         case OOROR:
712                 boolgen(n, 1, result, nn, Z);
713                 if(result == D_NONE)
714                         patch(p, pc);
715                 break;
716
717         case OCOMMA:
718                 cgen(l, D_NONE, l);
719                 doinc(l, POST);
720                 doinc(r, PRE);
721                 cgen(r, result, nn);
722                 break;
723
724         case ONOT:
725                 if(result == D_NONE) {
726                         nullwarn(l, Z);
727                         break;
728                 }
729                 boolgen(n, 1, result, nn, Z);
730                 break;
731
732         case OPOSTINC:
733         case OPOSTDEC:
734                 v = 1;
735                 if(l->type->etype == TIND)
736                         v = l->type->link->width;
737                 if(o == OPOSTDEC)
738                         v = -v;
739                 if(l->op == OBIT)
740                         goto bitinc;
741                 if(nn == Z)
742                         goto pre;
743
744                 lg = D_TREE;
745                 if(l->addable < INDEXED) {
746                         lg = regaddr(D_NONE);
747                         lcgen(l, lg, Z);
748                         lg |= I_INDIR;
749                 }
750                 if(result != D_NONE)
751                         gmove(l->type, nn->type, lg, l, result, nn);
752                 if(typefd[n->type->etype]) {
753                         rg = regalloc(n->type, D_NONE);
754                         gmove(l->type, l->type, lg, l, rg, l);
755                         gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
756                         gmove(l->type, l->type, rg, l, lg, l);
757                         regfree(rg);
758                 } else {
759                         if(v < 0)
760                                 gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
761                         else
762                                 gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
763                 }
764                 regfree(lg);
765                 break;
766
767         case OPREINC:
768         case OPREDEC:
769                 v = 1;
770                 if(l->type->etype == TIND)
771                         v = l->type->link->width;
772                 if(o == OPREDEC)
773                         v = -v;
774                 if(l->op == OBIT)
775                         goto bitinc;
776
777         pre:
778                 lg = D_TREE;
779                 if(l->addable < INDEXED) {
780                         lg = regaddr(D_NONE);
781                         lcgen(l, lg, Z);
782                         lg |= I_INDIR;
783                 }
784                 if(typefd[n->type->etype]) {
785                         rg = regalloc(n->type, D_NONE);
786                         gmove(l->type, l->type, lg, l, rg, l);
787                         gopcode(o, n->type, D_CONST, nodconst(1), rg, l);
788                         gmove(l->type, l->type, rg, l, lg, l);
789                         regfree(rg);
790                 } else {
791                         if(v < 0)
792                                 gopcode(o, n->type, D_CONST, nodconst(-v), lg, l);
793                         else
794                                 gopcode(o, n->type, D_CONST, nodconst(v), lg, l);
795                 }
796                 if(result != D_NONE)
797                         gmove(l->type, nn->type, lg, l, result, nn);
798                 regfree(lg);
799                 break;
800
801         bitinc:
802                 rg = regaddr(D_NONE);
803                 lg = regalloc(tfield, D_NONE);
804                 if(result != D_NONE && (o == OPOSTINC || o == OPOSTDEC)) {
805                         g = bitload(l, lg, rg, D_NONE, nn);
806                         if(nn != Z)
807                                 gmove(l->type, nn->type, g, l, result, nn);
808                         if(v < 0)
809                                 gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
810                         else
811                                 gopcode(o, n->type, D_CONST, nodconst(v), g, n);
812                         bitstore(l, g, rg, lg, D_NONE, nn);
813                         break;
814                 }
815                 g = bitload(l, lg, rg, result, nn);
816                 if(v < 0)
817                         gopcode(o, n->type, D_CONST, nodconst(-v), g, n);
818                 else
819                         gopcode(o, n->type, D_CONST, nodconst(v), g, n);
820                 if(result != D_NONE)
821                         gmove(l->type, nn->type, g, l, result, nn);
822                 bitstore(l, g, rg, lg, D_NONE, nn);
823                 break;
824         }
825 }
826
827 void
828 lcgen(Node *n, int result, Node *nn)
829 {
830         Node rn;
831         Prog *p1;
832         int lg;
833
834         if(n == Z || n->type == T)
835                 return;
836         if(debug['g']) {
837                 if(result == D_TREE)
838                         prtree(nn, "result");
839                 else
840                         print("result = %R\n", result);
841                 prtree(n, "lcgen");
842         }
843         if(nn == Z) {
844                 nn = &rn;
845                 nn->type = types[TIND];
846         }
847         switch(n->op) {
848         case OCOMMA:
849                 cgen(n->left, D_NONE, n->left);
850                 doinc(n->left, POST);
851                 doinc(n->right, PRE);
852                 lcgen(n->right, result, nn);
853                 break;
854
855         case OCOND:
856                 doinc(n->left, PRE);
857                 boolgen(n->left, 1, D_NONE, Z, n->left);
858                 p1 = p;
859
860                 inargs++;
861                 doinc(n->right->left, PRE);
862                 lcgen(n->right->left, result, nn);
863                 doinc(n->right->left, POST);
864                 gbranch(OGOTO);
865                 patch(p1, pc);
866                 p1 = p;
867
868                 doinc(n->right->right, PRE);
869                 lcgen(n->right->right, result, nn);
870                 doinc(n->right->right, POST);
871                 patch(p1, pc);
872                 inargs--;
873                 break;
874
875         case OIND:
876                 if(n->addable >= INDEXED) {
877                         if(result >= D_A0 && result < D_A0+NREG) {
878                                 gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
879                                 break;
880                         }
881                         if(result == D_TOS) {
882                                 gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
883                                 break;
884                         }
885                 }
886                 cgen(n->left, result, nn);
887                 break;
888
889         default:
890                 if(n->addable < INDEXED) {
891                         diag(n, "unknown op in lcgen: %O", n->op);
892                         break;
893                 }
894                 if(result >= D_A0 && result < D_A0+NREG) {
895                         gopcode(OADDR, types[TLONG], D_TREE, n, result, nn);
896                         break;
897                 }
898                 if(result == D_TOS) {
899                         gopcode(OADDR, types[TSHORT], D_NONE, nn, D_TREE, n);
900                         break;
901                 }
902                 lg = regaddr(result);
903                 gopcode(OADDR, types[TLONG], D_TREE, n, lg, nn);
904                 gopcode(OAS, nn->type, lg, nn, result, nn);
905                 regfree(lg);
906                 break;
907         }
908 }
909
910 void
911 bcgen(Node *n, int true)
912 {
913
914         boolgen(n, true, D_NONE, Z, Z);
915 }
916
917 void
918 boolgen(Node *n, int true, int result, Node *nn, Node *post)
919 {
920         Prog *p1, *p2;
921         Node *l, *r;
922         int lg, rg, fp, o;
923         long v;
924
925         if(debug['g']) {
926                 if(result == D_TREE)
927                         prtree(nn, "result");
928                 else
929                         print("result = %R\n", result);
930                 prtree(n, "boolgen");
931         }
932         l = n->left;
933         r = n->right;
934         switch(n->op) {
935
936         default:
937                 lg = eval(n, result);
938                 if(lg >= D_A0 && lg < D_A0+NREG) {
939                         rg = regalloc(types[TLONG], D_NONE);
940                         gopcode(OAS, types[TLONG], lg, n, rg, Z);
941                         regfree(rg);
942                 } else
943                         gopcode(OTST, n->type, D_NONE, Z, lg, n);
944                 regfree(lg);
945                 o = ONE;
946                 fp = typefd[n->type->etype];
947                 goto genbool;
948
949         case OCONST:
950                 fp = vconst(n);
951                 if(!true)
952                         fp = !fp;
953                 gbranch(OGOTO);
954                 if(fp) {
955                         p1 = p;
956                         gbranch(OGOTO);
957                         patch(p1, pc);
958                 }
959                 goto com;
960
961         case ONOT:
962                 boolgen(l, !true, result, nn, post);
963                 break;
964
965         case OCOND:
966                 doinc(l, PRE);
967                 boolgen(l, 1, D_NONE, Z, l);
968                 p1 = p;
969
970                 inargs++;
971                 doinc(r->left, PRE);
972                 boolgen(r->left, true, result, nn, r->left);
973                 if(result != D_NONE) {
974                         doinc(r->left, POST);
975                         gbranch(OGOTO);
976                         patch(p1, pc);
977                         p1 = p;
978
979                         doinc(r->right, PRE);
980                         boolgen(r->right, !true, result, nn, r->right);
981                         doinc(r->right, POST);
982                         patch(p1, pc);
983                         inargs--;
984                         break;
985                 }
986                 p2 = p;
987                 gbranch(OGOTO);
988                 patch(p1, pc);
989                 p1 = p;
990
991                 doinc(r->right, PRE);
992                 boolgen(r->right, !true, result, nn, r->right);
993                 patch(p2, pc);
994                 p2 = p;
995                 if(doinc(post, POST|TEST)) {
996                         lg = regalloc(types[TSHORT], D_NONE);
997                         gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
998                         doinc(post, POST);
999                         gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
1000                         regfree(lg);
1001                 }
1002                 gbranch(OGOTO);
1003                 patch(p1, pc);
1004                 patch(p2, pc);
1005                 inargs--;
1006                 goto com;
1007
1008         case OANDAND:
1009                 if(!true)
1010                         goto caseor;
1011
1012         caseand:
1013                 doinc(l, PRE);
1014                 boolgen(l, true, D_NONE, Z, l);
1015                 p1 = p;
1016                 inargs++;
1017                 doinc(r, PRE);
1018                 boolgen(r, !true, D_NONE, Z, r);
1019                 p2 = p;
1020                 patch(p1, pc);
1021                 gbranch(OGOTO);
1022                 patch(p2, pc);
1023                 inargs--;
1024                 goto com;
1025
1026         case OOROR:
1027                 if(!true)
1028                         goto caseand;
1029
1030         caseor:
1031                 doinc(l, PRE);
1032                 boolgen(l, !true, D_NONE, Z, l);
1033                 p1 = p;
1034                 inargs++;
1035                 doinc(r, PRE);
1036                 boolgen(r, !true, D_NONE, Z, r);
1037                 p2 = p;
1038                 gbranch(OGOTO);
1039                 patch(p1, pc);
1040                 patch(p2, pc);
1041                 inargs--;
1042                 goto com;
1043
1044         case OEQ:
1045         case ONE:
1046                 if(vconst(l) == 0) {
1047                         if(n->op == ONE) {
1048                                 boolgen(r, true, result, nn, post);
1049                                 break;
1050                         }
1051                         boolgen(r, !true, result, nn, post);
1052                         break;
1053                 }
1054
1055         case OLE:
1056         case OLT:
1057         case OGE:
1058         case OGT:
1059         case OHI:
1060         case OHS:
1061         case OLO:
1062         case OLS:
1063                 fp = typefd[r->type->etype];
1064                 if(l->op == OCONST) {
1065                         v = vconst(l);
1066                         if(v == 0) {    /* tst instruction */
1067                                 o = invrel[relindex(n->op)];
1068                                 rg = eval(r, result);
1069                                 gopcode(OTST, r->type, D_NONE, Z, rg, r);
1070                                 regfree(rg);
1071                                 goto genbool;
1072                         }
1073                         if(!fp) {       /* cmpi and movq, saves about .5% both time and space */
1074                                 if(v < 128 && v >= -128 &&
1075                                    ewidth[r->type->etype] == SZ_LONG) {
1076                                         rg = eval(r, result);
1077                                         lg = regalloc(l->type, D_NONE);
1078                                         cgen(l, lg, l);
1079                                         o = n->op;
1080                                         gopcode(o, l->type, lg, l, rg, r);
1081                                         regfree(lg);
1082                                         regfree(rg);
1083                                         goto genbool;
1084                                 }
1085                                 o = invrel[relindex(n->op)];
1086                                 rg = eval(r, result);
1087                                 gopcode(o, r->type, rg, r, D_TREE, l);
1088                                 regfree(rg);
1089                                 goto genbool;
1090                         }
1091                 }
1092                 lg = D_TOS;
1093                 if(r->complex < FNX)
1094                         lg = regalloc(l->type, lg);
1095                 cgen(l, lg, l);
1096                 v = argoff;
1097                 rg = eval(r, result);
1098                 if(lg == D_TOS) {
1099                         adjsp(v - argoff);
1100                         lg = regalloc(l->type, lg);
1101                         gopcode(OAS, l->type, D_TOS, l, lg, l);
1102                 }
1103                 o = n->op;
1104                 gopcode(o, l->type, lg, l, rg, r);
1105                 regfree(lg);
1106                 regfree(rg);
1107
1108         genbool:
1109                 if(true)
1110                         o = comrel[relindex(o)];
1111                 if(doinc(post, POST|TEST)) {
1112                         lg = regalloc(types[TSHORT], D_NONE);
1113                         gopcode(OAS, types[TSHORT], D_CCR, Z, lg, Z);
1114                         doinc(post, POST);
1115                         gopcode(OAS, types[TSHORT], lg, Z, D_CCR, Z);
1116                         regfree(lg);
1117                 }
1118                 gbranch(o);
1119                 if(fp)
1120                         fpbranch();
1121
1122         com:
1123                 if(result == D_NONE)
1124                         break;
1125                 p1 = p;
1126                 gopcode(OAS, nn->type, D_CONST, nodconst(1), result, nn);
1127                 gbranch(OGOTO);
1128                 p2 = p;
1129                 patch(p1, pc);
1130                 gopcode(OAS, nn->type, D_CONST, nodconst(0), result, nn);
1131                 patch(p2, pc);
1132                 break;
1133         }
1134 }
1135
1136 void
1137 sugen(Node *n, int result, Node *nn, long w)
1138 {
1139         long s, v, o;
1140         int lg, rg, ng;
1141         Prog *p1;
1142         Node *l, *r, nod;
1143         Type *t;
1144
1145         if(n == Z || n->type == T)
1146                 return;
1147         if(debug['g']) {
1148                 if(result == D_TREE)
1149                         prtree(nn, "result");
1150                 else
1151                         print("result = %R width = %ld\n", result, w);
1152                 prtree(n, "sugen");
1153         }
1154         s = argoff;
1155         if(result == D_TREE) {
1156                 if(nn == nodrat)
1157                         if(w > nrathole)
1158                                 nrathole = w;
1159         }
1160
1161         if(n->addable >= INDEXED && n->op != OCONST)
1162                 goto copy;
1163         switch(n->op) {
1164         default:
1165                 diag(n, "unknown op in sugen: %O", n->op);
1166                 break;
1167
1168         case OCONST:
1169                 if(n->type && typev[n->type->etype]) {
1170                         if(result == D_NONE) {
1171                                 nullwarn(n->left, Z);
1172                                 break;
1173                         }
1174
1175                         lg = regaddr(D_NONE);
1176                         if(result == D_TOS) {
1177                                 adjsp(s - argoff + w);
1178                                 gopcode(OADDR, types[TIND], result, nn, lg, n);
1179                         } else
1180                         if(result == D_TREE) {
1181                                 lcgen(nn, lg, Z);
1182                         } else
1183                                 diag(n, "unknown su result: %R", result);
1184
1185                         gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst>>32)),
1186                                 lg|I_INDINC, n);
1187                         gopcode(OAS, types[TLONG], D_CONST, nodconst((long)(n->vconst)),
1188                                 lg|I_INDINC, n);
1189                         regfree(lg);
1190                         break;
1191                 }
1192                 goto copy;
1193
1194         case ODOT:
1195                 l = n->left;
1196                 sugen(l, D_TREE, nodrat, l->type->width);
1197                 if(result != D_NONE) {
1198                         warn(n, "non-interruptable temporary");
1199                         nod = *nodrat;
1200                         r = n->right;
1201                         if(!r || r->op != OCONST) {
1202                                 diag(n, "DOT and no offset");
1203                                 break;
1204                         }
1205                         nod.xoffset += r->vconst;
1206                         nod.type = n->type;
1207                         sugen(&nod, result, nn, w);
1208                 }
1209                 break;
1210
1211         case OIND:
1212                 if(result == D_NONE) {
1213                         nullwarn(n->left, Z);
1214                         break;
1215                 }
1216                 goto copy;
1217
1218         case OSTRUCT:
1219                 lg = nodalloc(types[TIND], result, &nod);
1220                 nod.lineno = n->lineno;
1221                 if(result == D_TREE)
1222                         lcgen(nn, lg, Z);
1223                 else
1224                 if(result == D_TOS) {
1225                         adjsp(s - argoff + w);
1226                         gopcode(OADDR, types[TIND], result, nn, lg, n);
1227                 } else
1228                         diag(n, "unknown su result: %R", result);
1229                 o = 0;
1230                 r = n->left;
1231                 for(t = n->type->link; t != T; t = t->down) {
1232                         l = r;                  
1233                         if(r->op == OLIST) {
1234                                 l = r->left;
1235                                 r = r->right;
1236                         }
1237                         nod.type = t;
1238                         if(l->complex < FNX) {
1239                                 nod.xoffset = 0;
1240                                 if(o != t->offset) {
1241                                         gopcode(OADD, types[TIND], D_CONST,
1242                                                 nodconst(t->offset-o), lg, Z);
1243                                         o = t->offset;
1244                                 }
1245                                 cgen(l, D_TREE, &nod);
1246                                 continue;
1247                         }
1248                         nod.xoffset = t->offset - o;
1249                         gopcode(OAS, types[TIND], lg, Z, D_TOS, Z);
1250                         s = argoff;
1251                         if(typesuv[t->etype]) {
1252                                 sugen(l, D_TREE, nodrat, t->width);
1253                                 adjsp(s - argoff);
1254                                 gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
1255                                 warn(n, "non-interruptable temporary");
1256                                 sugen(nodrat, D_TREE, &nod, t->width);
1257                                 continue;
1258                         }
1259                         rg = regalloc(t, D_NONE);
1260                         cgen(l, rg, l);
1261                         adjsp(s - argoff);
1262                         gopcode(OAS, types[TIND], D_TOS, Z, lg, Z);
1263                         gopcode(OAS, t, rg, Z, D_TREE, &nod);
1264                         regfree(rg);
1265                 }
1266                 regfree(lg);
1267                 break;
1268
1269         case OAS:
1270                 if(result == D_NONE) {
1271                         sugen(n->right, D_TREE, n->left, w);
1272                         break;
1273                 }
1274                 sugen(n->right, D_TREE, nodrat, w);     /* could do better */
1275                 warn(n, "non-interruptable temporary");
1276                 sugen(nodrat, D_TREE, n->left, w);
1277                 sugen(nodrat, result, nn, w);
1278                 break;
1279
1280         case OFUNC:
1281                 if(result == D_NONE) {
1282                         sugen(n, D_TREE, nodrat, w);
1283                         break;
1284                 }
1285                 inargs++;
1286                 /* prepare zero-th arg: address of result */
1287                 if(result == D_TOS) {
1288                         adjsp(s - argoff + w);
1289                         v = argoff;
1290                         gargs(n->right);
1291                         gopcode(OADDR, types[TSHORT], D_NONE, nn, result, nn);
1292                         p->to.type = D_STACK;
1293                         p->to.offset = argoff - v;
1294                 } else
1295                 if(result == D_TREE) {
1296                         v = argoff;
1297                         gargs(n->right);
1298                         if(nn->complex >= FNX) {
1299                                 rg = regalloc(types[TIND], regret(types[TIND]));
1300                                 lcgen(nn, rg, Z);
1301                                 gopcode(OAS, types[TIND], rg, Z, D_TOS, Z);
1302                                 regfree(rg);
1303                         } else
1304                                 lcgen(nn, D_TOS, Z);
1305                 } else {
1306                         diag(n, "unknown result in FUNC sugen");
1307                         break;
1308                 }
1309                 argoff += types[TIND]->width;
1310                 l = n->left;
1311                 lg = D_TREE;
1312                 if(l->addable < INDEXED) {
1313                         lg = regaddr(result);
1314                         lcgen(l, lg, Z);
1315                         lg |= I_INDIR;
1316                 }
1317                 inargs--;
1318                 doinc(n->right, POST);
1319                 doinc(n->left, POST);
1320                 gopcode(OFUNC, types[TCHAR], D_NONE, Z, lg, l);
1321                 regfree(lg);
1322                 if(inargs)
1323                         adjsp(v - argoff);
1324                 break;
1325
1326         case OCOND:
1327                 doinc(n->left, PRE);
1328                 boolgen(n->left, 1, D_NONE, Z, n->left);
1329                 p1 = p;
1330
1331                 inargs++;
1332                 doinc(n->right->left, PRE);
1333                 sugen(n->right->left, result, nn, w);
1334                 doinc(n->right->left, POST);
1335                 gbranch(OGOTO);
1336                 patch(p1, pc);
1337                 p1 = p;
1338
1339                 doinc(n->right->right, PRE);
1340                 sugen(n->right->right, result, nn, w);
1341                 doinc(n->right->right, POST);
1342                 patch(p1, pc);
1343                 inargs--;
1344                 break;
1345
1346         case OCOMMA:
1347                 cgen(n->left, D_NONE, n->left);
1348                 doinc(n->left, POST);
1349                 doinc(n->right, PRE);
1350                 sugen(n->right, result, nn, w);
1351                 break;
1352         }
1353         return;
1354
1355 copy:
1356         if(result == D_NONE)
1357                 return;
1358         rg = regaddr(D_NONE);
1359         lcgen(n, rg, Z);
1360
1361         lg = regaddr(D_NONE);
1362         if(result == D_TOS) {
1363                 adjsp(s - argoff + w);
1364                 gopcode(OADDR, types[TIND], result, nn, lg, n);
1365         } else
1366         if(result == D_TREE) {
1367                 if(nn->complex >= FNX) {
1368                         gopcode(OAS, types[TIND], rg, n, D_TOS, n);
1369                         s = argoff;
1370                         lcgen(nn, lg, Z);
1371                         adjsp(s - argoff);
1372                         gopcode(OAS, types[TIND], D_TOS, n, rg, n);
1373                 } else
1374                         lcgen(nn, lg, Z);
1375         } else
1376                 diag(n, "unknown su result: %R", result);
1377
1378         if(w % SZ_LONG)
1379                 diag(Z, "sucopy width not 0%%%d", SZ_LONG);
1380         v = w / SZ_LONG;
1381         if(v & 1) {
1382                 gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
1383                 v--;
1384         }
1385         if(v > 6) {
1386                 ng = regalloc(types[TLONG], D_NONE);
1387                 gopcode(OAS, types[TLONG], D_CONST, nodconst(v/2-1), ng, n);
1388                 v = pc;
1389                 gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
1390                 gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
1391                 gbranch(OGT);
1392                 patch(p, v);
1393                 p->from.type = ng;
1394                 p->as = ADBF;
1395                 regfree(ng);
1396         } else
1397                 while(v > 0) {
1398                         gopcode(OAS, types[TLONG], rg|I_INDINC, n, lg|I_INDINC, n);
1399                         v--;
1400                 }
1401
1402         regfree(lg);
1403         regfree(rg);
1404 }