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