1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // TODO(rsc):
6 // assume CLD?
7
8 #include "gg.h"
9
10 void
11 mgen(Node *n, Node *n1, Node *rg)
12 {
13 Node n2;
14
15 n1->op = OEMPTY;
16
17 if(n->addable) {
18 *n1 = *n;
19 if(n1->op == OREGISTER || n1->op == OINDREG)
20 reg[n->val.u.reg]++;
21 return;
22 }
23 tempname(n1, n->type);
24 cgen(n, n1);
25 if(n->type->width <= widthptr || isfloat[n->type->etype]) {
26 n2 = *n1;
27 regalloc(n1, n->type, rg);
28 gmove(&n2, n1);
29 }
30 }
31
32 void
33 mfree(Node *n)
34 {
35 if(n->op == OREGISTER)
36 regfree(n);
37 }
38
39 /*
40 * generate:
41 * res = n;
42 * simplifies and calls gmove.
43 *
44 * TODO:
45 * sudoaddable
46 */
47 void
48 cgen(Node *n, Node *res)
49 {
50 Node *nl, *nr, *r, n1, n2, nt, f0, f1;
51 Prog *p1, *p2, *p3;
52 int a;
53
54 if(debug['g']) {
55 dump("\ncgen-n", n);
56 dump("cgen-res", res);
57 }
58
59 if(n == N || n->type == T)
60 fatal("cgen: n nil");
61 if(res == N || res->type == T)
62 fatal("cgen: res nil");
63
64 // inline slices
65 if(cgen_inline(n, res))
66 return;
67
68 while(n->op == OCONVNOP)
69 n = n->left;
70
71 // function calls on both sides? introduce temporary
72 if(n->ullman >= UINF && res->ullman >= UINF) {
73 tempname(&n1, n->type);
74 cgen(n, &n1);
75 cgen(&n1, res);
76 return;
77 }
78
79 // structs etc get handled specially
80 if(isfat(n->type)) {
81 if(n->type->width < 0)
82 fatal("forgot to compute width for %T", n->type);
83 sgen(n, res, n->type->width);
84 return;
85 }
86
87 // update addressability for string, slice
88 // can't do in walk because n->left->addable
89 // changes if n->left is an escaping local variable.
90 switch(n->op) {
91 case OLEN:
92 if(isslice(n->left->type) || istype(n->left->type, TSTRING))
93 n->addable = n->left->addable;
94 break;
95 case OCAP:
96 if(isslice(n->left->type))
97 n->addable = n->left->addable;
98 break;
99 }
100
101 // if both are addressable, move
102 if(n->addable && res->addable) {
103 gmove(n, res);
104 return;
105 }
106
107 // if both are not addressable, use a temporary.
108 if(!n->addable && !res->addable) {
109 // could use regalloc here sometimes,
110 // but have to check for ullman >= UINF.
111 tempname(&n1, n->type);
112 cgen(n, &n1);
113 cgen(&n1, res);
114 return;
115 }
116
117 // if result is not addressable directly but n is,
118 // compute its address and then store via the address.
119 if(!res->addable) {
120 igen(res, &n1, N);
121 cgen(n, &n1);
122 regfree(&n1);
123 return;
124 }
125
126 // complex types
127 if(complexop(n, res)) {
128 complexgen(n, res);
129 return;
130 }
131
132 // otherwise, the result is addressable but n is not.
133 // let's do some computation.
134
135 // use ullman to pick operand to eval first.
136 nl = n->left;
137 nr = n->right;
138 if(nl != N && nl->ullman >= UINF)
139 if(nr != N && nr->ullman >= UINF) {
140 // both are hard
141 tempname(&n1, nl->type);
142 cgen(nl, &n1);
143 n2 = *n;
144 n2.left = &n1;
145 cgen(&n2, res);
146 return;
147 }
148
149 // 64-bit ops are hard on 32-bit machine.
150 if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
151 switch(n->op) {
152 // math goes to cgen64.
153 case OMINUS:
154 case OCOM:
155 case OADD:
156 case OSUB:
157 case OMUL:
158 case OLSH:
159 case ORSH:
160 case OAND:
161 case OOR:
162 case OXOR:
163 cgen64(n, res);
164 return;
165 }
166 }
167
168 if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
169 goto flt;
170
171 switch(n->op) {
172 default:
173 dump("cgen", n);
174 fatal("cgen %O", n->op);
175 break;
176
177 case OREAL:
178 case OIMAG:
179 case OCOMPLEX:
180 fatal("unexpected complex");
181 return;
182
183 // these call bgen to get a bool value
184 case OOROR:
185 case OANDAND:
186 case OEQ:
187 case ONE:
188 case OLT:
189 case OLE:
190 case OGE:
191 case OGT:
192 case ONOT:
193 p1 = gbranch(AJMP, T);
194 p2 = pc;
195 gmove(nodbool(1), res);
196 p3 = gbranch(AJMP, T);
197 patch(p1, pc);
198 bgen(n, 1, p2);
199 gmove(nodbool(0), res);
200 patch(p3, pc);
201 return;
202
203 case OPLUS:
204 cgen(nl, res);
205 return;
206
207 case OMINUS:
208 case OCOM:
209 a = optoas(n->op, nl->type);
210 goto uop;
211
212 // symmetric binary
213 case OAND:
214 case OOR:
215 case OXOR:
216 case OADD:
217 case OMUL:
218 a = optoas(n->op, nl->type);
219 if(a == AIMULB) {
220 cgen_bmul(n->op, nl, nr, res);
221 break;
222 }
223 goto sbop;
224
225 // asymmetric binary
226 case OSUB:
227 a = optoas(n->op, nl->type);
228 goto abop;
229
230 case OCONV:
231 if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
232 cgen(nl, res);
233 break;
234 }
235
236 tempname(&n2, n->type);
237 mgen(nl, &n1, res);
238 gmove(&n1, &n2);
239 gmove(&n2, res);
240 mfree(&n1);
241 break;
242
243 case ODOT:
244 case ODOTPTR:
245 case OINDEX:
246 case OIND:
247 case ONAME: // PHEAP or PPARAMREF var
248 igen(n, &n1, res);
249 gmove(&n1, res);
250 regfree(&n1);
251 break;
252
253 case OLEN:
254 if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
255 // map has len in the first 32-bit word.
256 // a zero pointer means zero length
257 tempname(&n1, types[tptr]);
258 cgen(nl, &n1);
259 regalloc(&n2, types[tptr], N);
260 gmove(&n1, &n2);
261 n1 = n2;
262
263 nodconst(&n2, types[tptr], 0);
264 gins(optoas(OCMP, types[tptr]), &n1, &n2);
265 p1 = gbranch(optoas(OEQ, types[tptr]), T);
266
267 n2 = n1;
268 n2.op = OINDREG;
269 n2.type = types[TINT32];
270 gmove(&n2, &n1);
271
272 patch(p1, pc);
273
274 gmove(&n1, res);
275 regfree(&n1);
276 break;
277 }
278 if(istype(nl->type, TSTRING) || isslice(nl->type)) {
279 // both slice and string have len one pointer into the struct.
280 igen(nl, &n1, res);
281 n1.type = types[TUINT32];
282 n1.xoffset += Array_nel;
283 gmove(&n1, res);
284 regfree(&n1);
285 break;
286 }
287 fatal("cgen: OLEN: unknown type %lT", nl->type);
288 break;
289
290 case OCAP:
291 if(istype(nl->type, TCHAN)) {
292 // chan has cap in the second 32-bit word.
293 // a zero pointer means zero length
294 regalloc(&n1, types[tptr], res);
295 cgen(nl, &n1);
296
297 nodconst(&n2, types[tptr], 0);
298 gins(optoas(OCMP, types[tptr]), &n1, &n2);
299 p1 = gbranch(optoas(OEQ, types[tptr]), T);
300
301 n2 = n1;
302 n2.op = OINDREG;
303 n2.xoffset = 4;
304 n2.type = types[TINT32];
305 gmove(&n2, &n1);
306
307 patch(p1, pc);
308
309 gmove(&n1, res);
310 regfree(&n1);
311 break;
312 }
313 if(isslice(nl->type)) {
314 igen(nl, &n1, res);
315 n1.op = OINDREG;
316 n1.type = types[TUINT32];
317 n1.xoffset = Array_cap;
318 gmove(&n1, res);
319 regfree(&n1);
320 break;
321 }
322 fatal("cgen: OCAP: unknown type %lT", nl->type);
323 break;
324
325 case OADDR:
326 agen(nl, res);
327 break;
328
329 case OCALLMETH:
330 cgen_callmeth(n, 0);
331 cgen_callret(n, res);
332 break;
333
334 case OCALLINTER:
335 cgen_callinter(n, res, 0);
336 cgen_callret(n, res);
337 break;
338
339 case OCALLFUNC:
340 cgen_call(n, 0);
341 cgen_callret(n, res);
342 break;
343
344 case OMOD:
345 case ODIV:
346 cgen_div(n->op, nl, nr, res);
347 break;
348
349 case OLSH:
350 case ORSH:
351 cgen_shift(n->op, nl, nr, res);
352 break;
353 }
354 return;
355
356 sbop: // symmetric binary
357 if(nl->ullman < nr->ullman) {
358 r = nl;
359 nl = nr;
360 nr = r;
361 }
362
363 abop: // asymmetric binary
364 if(nl->ullman >= nr->ullman) {
365 tempname(&nt, nl->type);
366 cgen(nl, &nt);
367 mgen(nr, &n2, N);
368 regalloc(&n1, nl->type, res);
369 gmove(&nt, &n1);
370 gins(a, &n2, &n1);
371 gmove(&n1, res);
372 regfree(&n1);
373 mfree(&n2);
374 } else {
375 regalloc(&n2, nr->type, res);
376 cgen(nr, &n2);
377 regalloc(&n1, nl->type, N);
378 cgen(nl, &n1);
379 gins(a, &n2, &n1);
380 regfree(&n2);
381 gmove(&n1, res);
382 regfree(&n1);
383 }
384 return;
385
386 uop: // unary
387 tempname(&n1, nl->type);
388 cgen(nl, &n1);
389 gins(a, N, &n1);
390 gmove(&n1, res);
391 return;
392
393 flt: // floating-point. 387 (not SSE2) to interoperate with 8c
394 nodreg(&f0, nl->type, D_F0);
395 nodreg(&f1, n->type, D_F0+1);
396 if(nr != N)
397 goto flt2;
398
399 // unary
400 cgen(nl, &f0);
401 if(n->op != OCONV && n->op != OPLUS)
402 gins(foptoas(n->op, n->type, 0), N, N);
403 gmove(&f0, res);
404 return;
405
406 flt2: // binary
407 if(nl->ullman >= nr->ullman) {
408 cgen(nl, &f0);
409 if(nr->addable)
410 gins(foptoas(n->op, n->type, 0), nr, &f0);
411 else {
412 cgen(nr, &f0);
413 gins(foptoas(n->op, n->type, Fpop), &f0, &f1);
414 }
415 } else {
416 cgen(nr, &f0);
417 if(nl->addable)
418 gins(foptoas(n->op, n->type, Frev), nl, &f0);
419 else {
420 cgen(nl, &f0);
421 gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1);
422 }
423 }
424 gmove(&f0, res);
425 return;
426 }
427
428 /*
429 * generate array index into res.
430 * n might be any size; res is 32-bit.
431 * returns Prog* to patch to panic call.
432 */
433 Prog*
434 cgenindex(Node *n, Node *res)
435 {
436 Node tmp, lo, hi, zero;
437
438 if(!is64(n->type)) {
439 cgen(n, res);
440 return nil;
441 }
442
443 tempname(&tmp, types[TINT64]);
444 cgen(n, &tmp);
445 split64(&tmp, &lo, &hi);
446 gmove(&lo, res);
447 if(debug['B']) {
448 splitclean();
449 return nil;
450 }
451 nodconst(&zero, types[TINT32], 0);
452 gins(ACMPL, &hi, &zero);
453 splitclean();
454 return gbranch(AJNE, T);
455 }
456
457 /*
458 * address gen
459 * res = &n;
460 */
461 void
462 agen(Node *n, Node *res)
463 {
464 Node *nl, *nr;
465 Node n1, n2, n3, n4, tmp;
466 Type *t;
467 uint32 w;
468 uint64 v;
469 Prog *p1, *p2;
470
471 if(debug['g']) {
472 dump("\nagen-res", res);
473 dump("agen-r", n);
474 }
475 if(n == N || n->type == T || res == N || res->type == T)
476 fatal("agen");
477
478 while(n->op == OCONVNOP)
479 n = n->left;
480
481 // addressable var is easy
482 if(n->addable) {
483 if(n->op == OREGISTER)
484 fatal("agen OREGISTER");
485 regalloc(&n1, types[tptr], res);
486 gins(ALEAL, n, &n1);
487 gmove(&n1, res);
488 regfree(&n1);
489 return;
490 }
491
492 // let's compute
493 nl = n->left;
494 nr = n->right;
495
496 switch(n->op) {
497 default:
498 fatal("agen %O", n->op);
499
500 case OCALLMETH:
501 cgen_callmeth(n, 0);
502 cgen_aret(n, res);
503 break;
504
505 case OCALLINTER:
506 cgen_callinter(n, res, 0);
507 cgen_aret(n, res);
508 break;
509
510 case OCALLFUNC:
511 cgen_call(n, 0);
512 cgen_aret(n, res);
513 break;
514
515 case OINDEX:
516 p2 = nil; // to be patched to panicindex.
517 w = n->type->width;
518 if(nr->addable) {
519 if(!isconst(nr, CTINT))
520 tempname(&tmp, types[TINT32]);
521 if(!isconst(nl, CTSTR))
522 agenr(nl, &n3, res);
523 if(!isconst(nr, CTINT)) {
524 p2 = cgenindex(nr, &tmp);
525 regalloc(&n1, tmp.type, N);
526 gmove(&tmp, &n1);
527 }
528 } else if(nl->addable) {
529 if(!isconst(nr, CTINT)) {
530 tempname(&tmp, types[TINT32]);
531 p2 = cgenindex(nr, &tmp);
532 regalloc(&n1, tmp.type, N);
533 gmove(&tmp, &n1);
534 }
535 if(!isconst(nl, CTSTR)) {
536 regalloc(&n3, types[tptr], res);
537 agen(nl, &n3);
538 }
539 } else {
540 tempname(&tmp, types[TINT32]);
541 p2 = cgenindex(nr, &tmp);
542 nr = &tmp;
543 if(!isconst(nl, CTSTR))
544 agenr(nl, &n3, res);
545 regalloc(&n1, tmp.type, N);
546 gins(optoas(OAS, tmp.type), &tmp, &n1);
547 }
548
549 // &a is in &n3 (allocated in res)
550 // i is in &n1 (if not constant)
551 // w is width
552
553 // explicit check for nil if array is large enough
554 // that we might derive too big a pointer.
555 if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
556 regalloc(&n4, types[tptr], &n3);
557 gmove(&n3, &n4);
558 n4.op = OINDREG;
559 n4.type = types[TUINT8];
560 n4.xoffset = 0;
561 gins(ATESTB, nodintconst(0), &n4);
562 regfree(&n4);
563 }
564
565 // constant index
566 if(isconst(nr, CTINT)) {
567 if(isconst(nl, CTSTR))
568 fatal("constant string constant index");
569 v = mpgetfix(nr->val.u.xval);
570 if(isslice(nl->type) || nl->type->etype == TSTRING) {
571 if(!debug['B'] && !n->etype) {
572 n1 = n3;
573 n1.op = OINDREG;
574 n1.type = types[tptr];
575 n1.xoffset = Array_nel;
576 nodconst(&n2, types[TUINT32], v);
577 gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
578 p1 = gbranch(optoas(OGT, types[TUINT32]), T);
579 ginscall(panicindex, 0);
580 patch(p1, pc);
581 }
582
583 n1 = n3;
584 n1.op = OINDREG;
585 n1.type = types[tptr];
586 n1.xoffset = Array_array;
587 gmove(&n1, &n3);
588 }
589
590 if (v*w != 0) {
591 nodconst(&n2, types[tptr], v*w);
592 gins(optoas(OADD, types[tptr]), &n2, &n3);
593 }
594 gmove(&n3, res);
595 regfree(&n3);
596 break;
597 }
598
599 regalloc(&n2, types[TINT32], &n1); // i
600 gmove(&n1, &n2);
601 regfree(&n1);
602
603 if(!debug['B'] && !n->etype) {
604 // check bounds
605 if(isconst(nl, CTSTR))
606 nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
607 else if(isslice(nl->type) || nl->type->etype == TSTRING) {
608 n1 = n3;
609 n1.op = OINDREG;
610 n1.type = types[tptr];
611 n1.xoffset = Array_nel;
612 } else
613 nodconst(&n1, types[TUINT32], nl->type->bound);
614 gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
615 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
616 if(p2)
617 patch(p2, pc);
618 ginscall(panicindex, 0);
619 patch(p1, pc);
620 }
621
622 if(isconst(nl, CTSTR)) {
623 regalloc(&n3, types[tptr], res);
624 p1 = gins(ALEAL, N, &n3);
625 datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
626 p1->from.scale = 1;
627 p1->from.index = n2.val.u.reg;
628 goto indexdone;
629 }
630
631 if(isslice(nl->type) || nl->type->etype == TSTRING) {
632 n1 = n3;
633 n1.op = OINDREG;
634 n1.type = types[tptr];
635 n1.xoffset = Array_array;
636 gmove(&n1, &n3);
637 }
638
639 if(w == 0) {
640 // nothing to do
641 } else if(w == 1 || w == 2 || w == 4 || w == 8) {
642 p1 = gins(ALEAL, &n2, &n3);
643 p1->from.scale = w;
644 p1->from.index = p1->from.type;
645 p1->from.type = p1->to.type + D_INDIR;
646 } else {
647 nodconst(&n1, types[TUINT32], w);
648 gins(optoas(OMUL, types[TUINT32]), &n1, &n2);
649 gins(optoas(OADD, types[tptr]), &n2, &n3);
650 }
651
652 indexdone:
653 gmove(&n3, res);
654 regfree(&n2);
655 regfree(&n3);
656 break;
657
658 case ONAME:
659 // should only get here with names in this func.
660 if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
661 dump("bad agen", n);
662 fatal("agen: bad ONAME funcdepth %d != %d",
663 n->funcdepth, funcdepth);
664 }
665
666 // should only get here for heap vars or paramref
667 if(!(n->class & PHEAP) && n->class != PPARAMREF) {
668 dump("bad agen", n);
669 fatal("agen: bad ONAME class %#x", n->class);
670 }
671 cgen(n->heapaddr, res);
672 if(n->xoffset != 0) {
673 nodconst(&n1, types[tptr], n->xoffset);
674 gins(optoas(OADD, types[tptr]), &n1, res);
675 }
676 break;
677
678 case OIND:
679 cgen(nl, res);
680 break;
681
682 case ODOT:
683 t = nl->type;
684 agen(nl, res);
685 if(n->xoffset != 0) {
686 nodconst(&n1, types[tptr], n->xoffset);
687 gins(optoas(OADD, types[tptr]), &n1, res);
688 }
689 break;
690
691 case ODOTPTR:
692 t = nl->type;
693 if(!isptr[t->etype])
694 fatal("agen: not ptr %N", n);
695 cgen(nl, res);
696 if(n->xoffset != 0) {
697 // explicit check for nil if struct is large enough
698 // that we might derive too big a pointer.
699 if(nl->type->type->width >= unmappedzero) {
700 regalloc(&n1, types[tptr], res);
701 gmove(res, &n1);
702 n1.op = OINDREG;
703 n1.type = types[TUINT8];
704 n1.xoffset = 0;
705 gins(ATESTB, nodintconst(0), &n1);
706 regfree(&n1);
707 }
708 nodconst(&n1, types[tptr], n->xoffset);
709 gins(optoas(OADD, types[tptr]), &n1, res);
710 }
711 break;
712 }
713 }
714
715 /*
716 * generate:
717 * newreg = &n;
718 * res = newreg
719 *
720 * on exit, a has been changed to be *newreg.
721 * caller must regfree(a).
722 */
723 void
724 igen(Node *n, Node *a, Node *res)
725 {
726 Node n1;
727 Type *fp;
728 Iter flist;
729
730 switch(n->op) {
731 case ONAME:
732 if((n->class&PHEAP) || n->class == PPARAMREF)
733 break;
734 *a = *n;
735 return;
736
737 case OCALLFUNC:
738 fp = structfirst(&flist, getoutarg(n->left->type));
739 cgen_call(n, 0);
740 memset(a, 0, sizeof *a);
741 a->op = OINDREG;
742 a->val.u.reg = D_SP;
743 a->addable = 1;
744 a->xoffset = fp->width;
745 a->type = n->type;
746 return;
747 }
748 // release register for now, to avoid
749 // confusing tempname.
750 if(res != N && res->op == OREGISTER)
751 reg[res->val.u.reg]--;
752 tempname(&n1, types[tptr]);
753 agen(n, &n1);
754 if(res != N && res->op == OREGISTER)
755 reg[res->val.u.reg]++;
756 regalloc(a, types[tptr], res);
757 gmove(&n1, a);
758 a->op = OINDREG;
759 a->type = n->type;
760 }
761
762 /*
763 * generate:
764 * newreg = &n;
765 *
766 * caller must regfree(a).
767 */
768 void
769 agenr(Node *n, Node *a, Node *res)
770 {
771 Node n1;
772
773 tempname(&n1, types[tptr]);
774 agen(n, &n1);
775 regalloc(a, types[tptr], res);
776 gmove(&n1, a);
777 }
778
779 /*
780 * branch gen
781 * if(n == true) goto to;
782 */
783 void
784 bgen(Node *n, int true, Prog *to)
785 {
786 int et, a;
787 Node *nl, *nr, *r;
788 Node n1, n2, tmp, t1, t2, ax;
789 Prog *p1, *p2;
790
791 if(debug['g']) {
792 dump("\nbgen", n);
793 }
794
795 if(n == N)
796 n = nodbool(1);
797
798 if(n->ninit != nil)
799 genlist(n->ninit);
800
801 nl = n->left;
802 nr = n->right;
803
804 if(n->type == T) {
805 convlit(&n, types[TBOOL]);
806 if(n->type == T)
807 return;
808 }
809
810 et = n->type->etype;
811 if(et != TBOOL) {
812 yyerror("cgen: bad type %T for %O", n->type, n->op);
813 patch(gins(AEND, N, N), to);
814 return;
815 }
816 nl = N;
817 nr = N;
818
819 switch(n->op) {
820 default:
821 def:
822 regalloc(&n1, n->type, N);
823 cgen(n, &n1);
824 nodconst(&n2, n->type, 0);
825 gins(optoas(OCMP, n->type), &n1, &n2);
826 a = AJNE;
827 if(!true)
828 a = AJEQ;
829 patch(gbranch(a, n->type), to);
830 regfree(&n1);
831 return;
832
833 case OLITERAL:
834 // need to ask if it is bool?
835 if(!true == !n->val.u.bval)
836 patch(gbranch(AJMP, T), to);
837 return;
838
839 case ONAME:
840 if(!n->addable)
841 goto def;
842 nodconst(&n1, n->type, 0);
843 gins(optoas(OCMP, n->type), n, &n1);
844 a = AJNE;
845 if(!true)
846 a = AJEQ;
847 patch(gbranch(a, n->type), to);
848 return;
849
850 case OANDAND:
851 if(!true)
852 goto caseor;
853
854 caseand:
855 p1 = gbranch(AJMP, T);
856 p2 = gbranch(AJMP, T);
857 patch(p1, pc);
858 bgen(n->left, !true, p2);
859 bgen(n->right, !true, p2);
860 p1 = gbranch(AJMP, T);
861 patch(p1, to);
862 patch(p2, pc);
863 return;
864
865 case OOROR:
866 if(!true)
867 goto caseand;
868
869 caseor:
870 bgen(n->left, true, to);
871 bgen(n->right, true, to);
872 return;
873
874 case OEQ:
875 case ONE:
876 case OLT:
877 case OGT:
878 case OLE:
879 case OGE:
880 nr = n->right;
881 if(nr == N || nr->type == T)
882 return;
883
884 case ONOT: // unary
885 nl = n->left;
886 if(nl == N || nl->type == T)
887 return;
888 }
889
890 switch(n->op) {
891 case ONOT:
892 bgen(nl, !true, to);
893 break;
894
895 case OEQ:
896 case ONE:
897 case OLT:
898 case OGT:
899 case OLE:
900 case OGE:
901 a = n->op;
902 if(!true) {
903 if(isfloat[nl->type->etype]) {
904 // brcom is not valid on floats when NaN is involved.
905 p1 = gbranch(AJMP, T);
906 p2 = gbranch(AJMP, T);
907 patch(p1, pc);
908 bgen(n, 1, p2);
909 patch(gbranch(AJMP, T), to);
910 patch(p2, pc);
911 break;
912 }
913 a = brcom(a);
914 true = !true;
915 }
916
917 // make simplest on right
918 if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
919 a = brrev(a);
920 r = nl;
921 nl = nr;
922 nr = r;
923 }
924
925 if(isslice(nl->type)) {
926 // front end should only leave cmp to literal nil
927 if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
928 yyerror("illegal array comparison");
929 break;
930 }
931 a = optoas(a, types[tptr]);
932 regalloc(&n1, types[tptr], N);
933 agen(nl, &n1);
934 n2 = n1;
935 n2.op = OINDREG;
936 n2.xoffset = Array_array;
937 n2.type = types[tptr];
938 nodconst(&tmp, types[tptr], 0);
939 gins(optoas(OCMP, types[tptr]), &n2, &tmp);
940 patch(gbranch(a, types[tptr]), to);
941 regfree(&n1);
942 break;
943 }
944
945 if(isinter(nl->type)) {
946 // front end should only leave cmp to literal nil
947 if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
948 yyerror("illegal interface comparison");
949 break;
950 }
951 a = optoas(a, types[tptr]);
952 regalloc(&n1, types[tptr], N);
953 agen(nl, &n1);
954 n2 = n1;
955 n2.op = OINDREG;
956 n2.xoffset = 0;
957 nodconst(&tmp, types[tptr], 0);
958 gins(optoas(OCMP, types[tptr]), &n2, &tmp);
959 patch(gbranch(a, types[tptr]), to);
960 regfree(&n1);
961 break;
962 }
963
964 if(isfloat[nr->type->etype]) {
965 a = brrev(a); // because the args are stacked
966 if(a == OGE || a == OGT) {
967 // only < and <= work right with NaN; reverse if needed
968 r = nr;
969 nr = nl;
970 nl = r;
971 a = brrev(a);
972 }
973 nodreg(&tmp, nr->type, D_F0);
974 nodreg(&n2, nr->type, D_F0 + 1);
975 nodreg(&ax, types[TUINT16], D_AX);
976 et = simsimtype(nr->type);
977 if(et == TFLOAT64) {
978 if(nl->ullman > nr->ullman) {
979 cgen(nl, &tmp);
980 cgen(nr, &tmp);
981 gins(AFXCHD, &tmp, &n2);
982 } else {
983 cgen(nr, &tmp);
984 cgen(nl, &tmp);
985 }
986 gins(AFUCOMIP, &tmp, &n2);
987 gins(AFMOVDP, &tmp, &tmp); // annoying pop but still better than STSW+SAHF
988 } else {
989 // TODO(rsc): The moves back and forth to memory
990 // here are for truncating the value to 32 bits.
991 // This handles 32-bit comparison but presumably
992 // all the other ops have the same problem.
993 // We need to figure out what the right general
994 // solution is, besides telling people to use float64.
995 tempname(&t1, types[TFLOAT32]);
996 tempname(&t2, types[TFLOAT32]);
997 cgen(nr, &t1);
998 cgen(nl, &t2);
999 gmove(&t2, &tmp);
1000 gins(AFCOMFP, &t1, &tmp);
1001 gins(AFSTSW, N, &ax);
1002 gins(ASAHF, N, N);
1003 }
1004 if(a == OEQ) {
1005 // neither NE nor P
1006 p1 = gbranch(AJNE, T);
1007 p2 = gbranch(AJPS, T);
1008 patch(gbranch(AJMP, T), to);
1009 patch(p1, pc);
1010 patch(p2, pc);
1011 } else if(a == ONE) {
1012 // either NE or P
1013 patch(gbranch(AJNE, T), to);
1014 patch(gbranch(AJPS, T), to);
1015 } else
1016 patch(gbranch(optoas(a, nr->type), T), to);
1017 break;
1018 }
1019 if(iscomplex[nl->type->etype]) {
1020 complexbool(a, nl, nr, true, to);
1021 break;
1022 }
1023
1024 if(is64(nr->type)) {
1025 if(!nl->addable) {
1026 tempname(&n1, nl->type);
1027 cgen(nl, &n1);
1028 nl = &n1;
1029 }
1030 if(!nr->addable) {
1031 tempname(&n2, nr->type);
1032 cgen(nr, &n2);
1033 nr = &n2;
1034 }
1035 cmp64(nl, nr, a, to);
1036 break;
1037 }
1038
1039 a = optoas(a, nr->type);
1040
1041 if(nr->ullman >= UINF) {
1042 tempname(&n1, nl->type);
1043 tempname(&tmp, nr->type);
1044 cgen(nl, &n1);
1045 cgen(nr, &tmp);
1046 regalloc(&n2, nr->type, N);
1047 cgen(&tmp, &n2);
1048 goto cmp;
1049 }
1050
1051 tempname(&n1, nl->type);
1052 cgen(nl, &n1);
1053
1054 if(smallintconst(nr)) {
1055 gins(optoas(OCMP, nr->type), &n1, nr);
1056 patch(gbranch(a, nr->type), to);
1057 break;
1058 }
1059
1060 tempname(&tmp, nr->type);
1061 cgen(nr, &tmp);
1062 regalloc(&n2, nr->type, N);
1063 gmove(&tmp, &n2);
1064
1065 cmp:
1066 gins(optoas(OCMP, nr->type), &n1, &n2);
1067 patch(gbranch(a, nr->type), to);
1068 regfree(&n2);
1069 break;
1070 }
1071 }
1072
1073 /*
1074 * n is on stack, either local variable
1075 * or return value from function call.
1076 * return n's offset from SP.
1077 */
1078 int32
1079 stkof(Node *n)
1080 {
1081 Type *t;
1082 Iter flist;
1083 int32 off;
1084
1085 switch(n->op) {
1086 case OINDREG:
1087 return n->xoffset;
1088
1089 case ODOT:
1090 t = n->left->type;
1091 if(isptr[t->etype])
1092 break;
1093 off = stkof(n->left);
1094 if(off == -1000 || off == 1000)
1095 return off;
1096 return off + n->xoffset;
1097
1098 case OINDEX:
1099 t = n->left->type;
1100 if(!isfixedarray(t))
1101 break;
1102 off = stkof(n->left);
1103 if(off == -1000 || off == 1000)
1104 return off;
1105 if(isconst(n->right, CTINT))
1106 return off + t->type->width * mpgetfix(n->right->val.u.xval);
1107 return 1000;
1108
1109 case OCALLMETH:
1110 case OCALLINTER:
1111 case OCALLFUNC:
1112 t = n->left->type;
1113 if(isptr[t->etype])
1114 t = t->type;
1115
1116 t = structfirst(&flist, getoutarg(t));
1117 if(t != T)
1118 return t->width;
1119 break;
1120 }
1121
1122 // botch - probably failing to recognize address
1123 // arithmetic on the above. eg INDEX and DOT
1124 return -1000;
1125 }
1126
1127 /*
1128 * struct gen
1129 * memmove(&res, &n, w);
1130 */
1131 void
1132 sgen(Node *n, Node *res, int32 w)
1133 {
1134 Node dst, src, tdst, tsrc;
1135 int32 c, q, odst, osrc;
1136
1137 if(debug['g']) {
1138 print("\nsgen w=%d\n", w);
1139 dump("r", n);
1140 dump("res", res);
1141 }
1142 if(w == 0)
1143 return;
1144 if(n->ullman >= UINF && res->ullman >= UINF) {
1145 fatal("sgen UINF");
1146 }
1147
1148 if(w < 0)
1149 fatal("sgen copy %d", w);
1150
1151 // offset on the stack
1152 osrc = stkof(n);
1153 odst = stkof(res);
1154
1155 if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
1156 // osrc and odst both on stack, and at least one is in
1157 // an unknown position. Could generate code to test
1158 // for forward/backward copy, but instead just copy
1159 // to a temporary location first.
1160 tempname(&tsrc, n->type);
1161 sgen(n, &tsrc, w);
1162 sgen(&tsrc, res, w);
1163 return;
1164 }
1165
1166 nodreg(&dst, types[tptr], D_DI);
1167 nodreg(&src, types[tptr], D_SI);
1168
1169 tempname(&tsrc, types[tptr]);
1170 tempname(&tdst, types[tptr]);
1171 if(!n->addable)
1172 agen(n, &tsrc);
1173 if(!res->addable)
1174 agen(res, &tdst);
1175 if(n->addable)
1176 agen(n, &src);
1177 else
1178 gmove(&tsrc, &src);
1179 if(res->addable)
1180 agen(res, &dst);
1181 else
1182 gmove(&tdst, &dst);
1183
1184 c = w % 4; // bytes
1185 q = w / 4; // doublewords
1186
1187 // if we are copying forward on the stack and
1188 // the src and dst overlap, then reverse direction
1189 if(osrc < odst && odst < osrc+w) {
1190 // reverse direction
1191 gins(ASTD, N, N); // set direction flag
1192 if(c > 0) {
1193 gconreg(AADDL, w-1, D_SI);
1194 gconreg(AADDL, w-1, D_DI);
1195
1196 gconreg(AMOVL, c, D_CX);
1197 gins(AREP, N, N); // repeat
1198 gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)-
1199 }
1200
1201 if(q > 0) {
1202 if(c > 0) {
1203 gconreg(AADDL, -3, D_SI);
1204 gconreg(AADDL, -3, D_DI);
1205 } else {
1206 gconreg(AADDL, w-4, D_SI);
1207 gconreg(AADDL, w-4, D_DI);
1208 }
1209 gconreg(AMOVL, q, D_CX);
1210 gins(AREP, N, N); // repeat
1211 gins(AMOVSL, N, N); // MOVL *(SI)-,*(DI)-
1212 }
1213 // we leave with the flag clear
1214 gins(ACLD, N, N);
1215 } else {
1216 gins(ACLD, N, N); // paranoia. TODO(rsc): remove?
1217 // normal direction
1218 if(q >= 4) {
1219 gconreg(AMOVL, q, D_CX);
1220 gins(AREP, N, N); // repeat
1221 gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
1222 } else
1223 while(q > 0) {
1224 gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
1225 q--;
1226 }
1227 while(c > 0) {
1228 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+
1229 c--;
1230 }
1231 }
1232 }
1233