LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #undef EXTERN | 5 #undef EXTERN |
6 #define EXTERN | 6 #define EXTERN |
7 #include <u.h> | 7 #include <u.h> |
8 #include <libc.h> | 8 #include <libc.h> |
9 #include "gg.h" | 9 #include "gg.h" |
10 #include "opt.h" | 10 #include "opt.h" |
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 | 595 |
596 /* | 596 /* |
597 * generate division according to op, one of: | 597 * generate division according to op, one of: |
598 * res = nl / nr | 598 * res = nl / nr |
599 * res = nl % nr | 599 * res = nl % nr |
600 */ | 600 */ |
601 void | 601 void |
602 cgen_div(int op, Node *nl, Node *nr, Node *res) | 602 cgen_div(int op, Node *nl, Node *nr, Node *res) |
603 { | 603 { |
604 Node n1, n2, n3; | 604 Node n1, n2, n3; |
605 Node ax, dx, oldax, olddx; | |
606 int w, a; | 605 int w, a; |
607 Magic m; | 606 Magic m; |
608 | 607 |
609 if(nr->op != OLITERAL) | 608 if(nr->op != OLITERAL) |
610 goto longdiv; | 609 goto longdiv; |
611 w = nl->type->width*8; | 610 w = nl->type->width*8; |
612 | 611 |
613 » goto divbymul; | 612 » // Front end handled 32-bit division. We only need to handle 64-bit. |
614 | |
615 divbymul: | |
616 // try to do division by multiply by (2^w)/d | 613 // try to do division by multiply by (2^w)/d |
617 // see hacker's delight chapter 10 | 614 // see hacker's delight chapter 10 |
618 switch(simtype[nl->type->etype]) { | 615 switch(simtype[nl->type->etype]) { |
619 default: | 616 default: |
620 goto longdiv; | 617 goto longdiv; |
621 | 618 |
622 case TUINT8: | |
623 case TUINT16: | |
624 case TUINT32: | |
625 case TUINT64: | 619 case TUINT64: |
626 m.w = w; | 620 m.w = w; |
627 m.ud = mpgetfix(nr->val.u.xval); | 621 m.ud = mpgetfix(nr->val.u.xval); |
628 umagic(&m); | 622 umagic(&m); |
629 if(m.bad) | 623 if(m.bad) |
630 break; | 624 break; |
631 if(op == OMOD) | 625 if(op == OMOD) |
632 goto longmod; | 626 goto longmod; |
633 | 627 |
634 » » regalloc(&n1, nl->type, N); | 628 » » cgenr(nl, &n1, N); |
635 » » cgen(nl, &n1);» » » » // num -> reg(n1) | |
636 | |
637 » » savex(D_AX, &ax, &oldax, res, nl->type); | |
638 » » savex(D_DX, &dx, &olddx, res, nl->type); | |
639 | |
640 nodconst(&n2, nl->type, m.um); | 629 nodconst(&n2, nl->type, m.um); |
641 » » gmove(&n2, &ax);» » » // const->ax | 630 » » regalloc(&n3, nl->type, res); |
642 | 631 » » cgen_hmul(&n1, &n2, &n3); |
643 » » gins(optoas(OHMUL, nl->type), &n1, N);» // imul reg | |
644 » » if(w == 8) { | |
645 » » » // fix up 8-bit multiply | |
646 » » » Node ah, dl; | |
647 » » » nodreg(&ah, types[TUINT8], D_AH); | |
648 » » » nodreg(&dl, types[TUINT8], D_DL); | |
649 » » » gins(AMOVB, &ah, &dl); | |
650 » » } | |
651 | 632 |
652 if(m.ua) { | 633 if(m.ua) { |
653 // need to add numerator accounting for overflow | 634 // need to add numerator accounting for overflow |
654 » » » gins(optoas(OADD, nl->type), &n1, &dx); | 635 » » » gins(optoas(OADD, nl->type), &n1, &n3); |
655 nodconst(&n2, nl->type, 1); | 636 nodconst(&n2, nl->type, 1); |
656 » » » gins(optoas(ORROTC, nl->type), &n2, &dx); | 637 » » » gins(optoas(ORROTC, nl->type), &n2, &n3); |
657 nodconst(&n2, nl->type, m.s-1); | 638 nodconst(&n2, nl->type, m.s-1); |
658 » » » gins(optoas(ORSH, nl->type), &n2, &dx); | 639 » » » gins(optoas(ORSH, nl->type), &n2, &n3); |
659 } else { | 640 } else { |
660 nodconst(&n2, nl->type, m.s); | 641 nodconst(&n2, nl->type, m.s); |
661 » » » gins(optoas(ORSH, nl->type), &n2, &dx);»// shift dx | 642 » » » gins(optoas(ORSH, nl->type), &n2, &n3);»// shift dx |
662 » » } | 643 » » } |
663 | 644 |
664 | 645 » » gmove(&n3, res); |
665 regfree(&n1); | 646 regfree(&n1); |
666 » » gmove(&dx, res); | 647 » » regfree(&n3); |
667 | |
668 » » restx(&ax, &oldax); | |
669 » » restx(&dx, &olddx); | |
670 return; | 648 return; |
671 | 649 |
672 case TINT8: | |
673 case TINT16: | |
674 case TINT32: | |
675 case TINT64: | 650 case TINT64: |
676 m.w = w; | 651 m.w = w; |
677 m.sd = mpgetfix(nr->val.u.xval); | 652 m.sd = mpgetfix(nr->val.u.xval); |
678 smagic(&m); | 653 smagic(&m); |
679 if(m.bad) | 654 if(m.bad) |
680 break; | 655 break; |
681 if(op == OMOD) | 656 if(op == OMOD) |
682 goto longmod; | 657 goto longmod; |
683 | 658 |
684 » » regalloc(&n1, nl->type, N); | 659 » » cgenr(nl, &n1, res); |
685 » » cgen(nl, &n1);» » » » // num -> reg(n1) | |
686 | |
687 » » savex(D_AX, &ax, &oldax, res, nl->type); | |
688 » » savex(D_DX, &dx, &olddx, res, nl->type); | |
689 | |
690 nodconst(&n2, nl->type, m.sm); | 660 nodconst(&n2, nl->type, m.sm); |
691 » » gmove(&n2, &ax);» » » // const->ax | 661 » » regalloc(&n3, nl->type, N); |
692 | 662 » » cgen_hmul(&n1, &n2, &n3); |
693 » » gins(optoas(OHMUL, nl->type), &n1, N);» // imul reg | |
694 » » if(w == 8) { | |
695 » » » // fix up 8-bit multiply | |
696 » » » Node ah, dl; | |
697 » » » nodreg(&ah, types[TUINT8], D_AH); | |
698 » » » nodreg(&dl, types[TUINT8], D_DL); | |
699 » » » gins(AMOVB, &ah, &dl); | |
700 » » } | |
701 | 663 |
702 if(m.sm < 0) { | 664 if(m.sm < 0) { |
703 // need to add numerator | 665 // need to add numerator |
704 » » » gins(optoas(OADD, nl->type), &n1, &dx); | 666 » » » gins(optoas(OADD, nl->type), &n1, &n3); |
705 } | 667 } |
706 | 668 |
707 nodconst(&n2, nl->type, m.s); | 669 nodconst(&n2, nl->type, m.s); |
708 » » gins(optoas(ORSH, nl->type), &n2, &dx);»// shift dx | 670 » » gins(optoas(ORSH, nl->type), &n2, &n3);»// shift n3 |
709 | 671 |
710 nodconst(&n2, nl->type, w-1); | 672 nodconst(&n2, nl->type, w-1); |
711 gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg | 673 gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg |
712 » » gins(optoas(OSUB, nl->type), &n1, &dx);»// added | 674 » » gins(optoas(OSUB, nl->type), &n1, &n3);»// added |
713 | 675 |
714 if(m.sd < 0) { | 676 if(m.sd < 0) { |
715 // this could probably be removed | 677 // this could probably be removed |
716 // by factoring it into the multiplier | 678 // by factoring it into the multiplier |
717 » » » gins(optoas(OMINUS, nl->type), N, &dx); | 679 » » » gins(optoas(OMINUS, nl->type), N, &n3); |
718 » » } | 680 » » } |
719 | 681 |
| 682 » » gmove(&n3, res); |
720 regfree(&n1); | 683 regfree(&n1); |
721 » » gmove(&dx, res); | 684 » » regfree(&n3); |
722 | |
723 » » restx(&ax, &oldax); | |
724 » » restx(&dx, &olddx); | |
725 return; | 685 return; |
726 } | 686 } |
727 goto longdiv; | 687 goto longdiv; |
728 | 688 |
729 longdiv: | 689 longdiv: |
730 // division and mod using (slow) hardware instruction | 690 // division and mod using (slow) hardware instruction |
731 dodiv(op, nl, nr, res); | 691 dodiv(op, nl, nr, res); |
732 return; | 692 return; |
733 | 693 |
734 longmod: | 694 longmod: |
(...skipping 13 matching lines...) Expand all Loading... |
748 regalloc(&n3, nl->type, N); | 708 regalloc(&n3, nl->type, N); |
749 cgen(nr, &n3); | 709 cgen(nr, &n3); |
750 gins(a, &n3, &n2); | 710 gins(a, &n3, &n2); |
751 regfree(&n3); | 711 regfree(&n3); |
752 } else | 712 } else |
753 gins(a, nr, &n2); | 713 gins(a, nr, &n2); |
754 gins(optoas(OSUB, nl->type), &n2, &n1); | 714 gins(optoas(OSUB, nl->type), &n2, &n1); |
755 gmove(&n1, res); | 715 gmove(&n1, res); |
756 regfree(&n1); | 716 regfree(&n1); |
757 regfree(&n2); | 717 regfree(&n2); |
| 718 } |
| 719 |
| 720 /* |
| 721 * generate high multiply: |
| 722 * res = (nl*nr) >> width |
| 723 */ |
| 724 void |
| 725 cgen_hmul(Node *nl, Node *nr, Node *res) |
| 726 { |
| 727 Type *t; |
| 728 int a; |
| 729 Node n1, n2, ax, dx, *tmp; |
| 730 |
| 731 t = nl->type; |
| 732 a = optoas(OHMUL, t); |
| 733 if(nl->ullman < nr->ullman) { |
| 734 tmp = nl; |
| 735 nl = nr; |
| 736 nr = tmp; |
| 737 } |
| 738 cgenr(nl, &n1, res); |
| 739 cgenr(nr, &n2, N); |
| 740 nodreg(&ax, t, D_AX); |
| 741 gmove(&n1, &ax); |
| 742 gins(a, &n2, N); |
| 743 regfree(&n2); |
| 744 regfree(&n1); |
| 745 |
| 746 if(t->width == 1) { |
| 747 // byte multiply behaves differently. |
| 748 nodreg(&ax, t, D_AH); |
| 749 nodreg(&dx, t, D_DL); |
| 750 gmove(&ax, &dx); |
| 751 } |
| 752 nodreg(&dx, t, D_DX); |
| 753 gmove(&dx, res); |
758 } | 754 } |
759 | 755 |
760 /* | 756 /* |
761 * generate shift according to op, one of: | 757 * generate shift according to op, one of: |
762 * res = nl << nr | 758 * res = nl << nr |
763 * res = nl >> nr | 759 * res = nl >> nr |
764 */ | 760 */ |
765 void | 761 void |
766 cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) | 762 cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) |
767 { | 763 { |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
950 gins(ASTOSB, N, N); // STOB AL,*(DI)+ | 946 gins(ASTOSB, N, N); // STOB AL,*(DI)+ |
951 } else | 947 } else |
952 while(c > 0) { | 948 while(c > 0) { |
953 gins(ASTOSB, N, N); // STOB AL,*(DI)+ | 949 gins(ASTOSB, N, N); // STOB AL,*(DI)+ |
954 c--; | 950 c--; |
955 } | 951 } |
956 | 952 |
957 restx(&n1, &oldn1); | 953 restx(&n1, &oldn1); |
958 restx(&ax, &oldax); | 954 restx(&ax, &oldax); |
959 } | 955 } |
LEFT | RIGHT |