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