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