LEFT | RIGHT |
(no file at all) | |
1 // Derived from Inferno utils/8c/txt.c | 1 // Derived from Inferno utils/8c/txt.c |
2 // http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c | 2 // http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c |
3 // | 3 // |
4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. | 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. |
5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) | 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) |
6 // Portions Copyright © 1997-1999 Vita Nuova Limited | 6 // Portions Copyright © 1997-1999 Vita Nuova Limited |
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuov
a.com) | 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuov
a.com) |
8 // Portions Copyright © 2004,2006 Bruce Ellis | 8 // Portions Copyright © 2004,2006 Bruce Ellis |
9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) | 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) |
10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others | 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others |
(...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 a = ACDQ; | 683 a = ACDQ; |
684 break; | 684 break; |
685 } | 685 } |
686 return a; | 686 return a; |
687 } | 687 } |
688 | 688 |
689 #define FCASE(a, b, c) (((a)<<16)|((b)<<8)|(c)) | 689 #define FCASE(a, b, c) (((a)<<16)|((b)<<8)|(c)) |
690 int | 690 int |
691 foptoas(int op, Type *t, int flg) | 691 foptoas(int op, Type *t, int flg) |
692 { | 692 { |
693 » int et; | 693 » int et, a; |
694 | 694 |
695 et = simtype[t->etype]; | 695 et = simtype[t->etype]; |
| 696 |
| 697 if(use_sse) |
| 698 goto sse; |
696 | 699 |
697 // If we need Fpop, it means we're working on | 700 // If we need Fpop, it means we're working on |
698 // two different floating-point registers, not memory. | 701 // two different floating-point registers, not memory. |
699 // There the instruction only has a float64 form. | 702 // There the instruction only has a float64 form. |
700 if(flg & Fpop) | 703 if(flg & Fpop) |
701 et = TFLOAT64; | 704 et = TFLOAT64; |
702 | 705 |
703 // clear Frev if unneeded | 706 // clear Frev if unneeded |
704 switch(op) { | 707 switch(op) { |
705 case OADD: | 708 case OADD: |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 return AFCOMDPP; | 766 return AFCOMDPP; |
764 ········ | 767 ········ |
765 case FCASE(OMINUS, TFLOAT32, 0): | 768 case FCASE(OMINUS, TFLOAT32, 0): |
766 return AFCHS; | 769 return AFCHS; |
767 case FCASE(OMINUS, TFLOAT64, 0): | 770 case FCASE(OMINUS, TFLOAT64, 0): |
768 return AFCHS; | 771 return AFCHS; |
769 } | 772 } |
770 | 773 |
771 fatal("foptoas %O %T %#x", op, t, flg); | 774 fatal("foptoas %O %T %#x", op, t, flg); |
772 return 0; | 775 return 0; |
773 } | 776 |
| 777 sse: |
| 778 » switch(CASE(op, et)) { |
| 779 » default: |
| 780 » » fatal("foptoas-sse: no entry %O-%T", op, t); |
| 781 » » break; |
| 782 |
| 783 » case CASE(OCMP, TFLOAT32): |
| 784 » » a = AUCOMISS; |
| 785 » » break; |
| 786 |
| 787 » case CASE(OCMP, TFLOAT64): |
| 788 » » a = AUCOMISD; |
| 789 » » break; |
| 790 |
| 791 » case CASE(OAS, TFLOAT32): |
| 792 » » a = AMOVSS; |
| 793 » » break; |
| 794 |
| 795 » case CASE(OAS, TFLOAT64): |
| 796 » » a = AMOVSD; |
| 797 » » break; |
| 798 |
| 799 » case CASE(OADD, TFLOAT32): |
| 800 » » a = AADDSS; |
| 801 » » break; |
| 802 |
| 803 » case CASE(OADD, TFLOAT64): |
| 804 » » a = AADDSD; |
| 805 » » break; |
| 806 |
| 807 » case CASE(OSUB, TFLOAT32): |
| 808 » » a = ASUBSS; |
| 809 » » break; |
| 810 |
| 811 » case CASE(OSUB, TFLOAT64): |
| 812 » » a = ASUBSD; |
| 813 » » break; |
| 814 |
| 815 » case CASE(OMUL, TFLOAT32): |
| 816 » » a = AMULSS; |
| 817 » » break; |
| 818 |
| 819 » case CASE(OMUL, TFLOAT64): |
| 820 » » a = AMULSD; |
| 821 » » break; |
| 822 |
| 823 » case CASE(ODIV, TFLOAT32): |
| 824 » » a = ADIVSS; |
| 825 » » break; |
| 826 |
| 827 » case CASE(ODIV, TFLOAT64): |
| 828 » » a = ADIVSD; |
| 829 » » break; |
| 830 » } |
| 831 » return a; |
| 832 } |
| 833 |
774 | 834 |
775 static int resvd[] = | 835 static int resvd[] = |
776 { | 836 { |
777 // D_DI, // for movstring | 837 // D_DI, // for movstring |
778 // D_SI, // for movstring | 838 // D_SI, // for movstring |
779 | 839 |
780 D_AX, // for divide | 840 D_AX, // for divide |
781 D_CX, // for shift | 841 D_CX, // for shift |
782 D_DX, // for divide | 842 D_DX, // for divide |
783 D_SP, // for stack | 843 D_SP, // for stack |
784 | 844 |
785 D_BL, // because D_BX can be allocated | 845 D_BL, // because D_BX can be allocated |
786 D_BH, | 846 D_BH, |
787 }; | 847 }; |
788 | 848 |
789 void | 849 void |
790 ginit(void) | 850 ginit(void) |
791 { | 851 { |
792 int i; | 852 int i; |
793 | 853 |
794 for(i=0; i<nelem(reg); i++) | 854 for(i=0; i<nelem(reg); i++) |
795 reg[i] = 1; | 855 reg[i] = 1; |
796 for(i=D_AX; i<=D_DI; i++) | 856 for(i=D_AX; i<=D_DI; i++) |
797 reg[i] = 0; | 857 reg[i] = 0; |
| 858 for(i=D_X0; i<=D_X7; i++) |
| 859 reg[i] = 0; |
798 for(i=0; i<nelem(resvd); i++) | 860 for(i=0; i<nelem(resvd); i++) |
799 reg[resvd[i]]++; | 861 reg[resvd[i]]++; |
800 } | 862 } |
801 | 863 |
802 uintptr regpc[D_NONE]; | 864 uintptr regpc[D_NONE]; |
803 | 865 |
804 void | 866 void |
805 gclean(void) | 867 gclean(void) |
806 { | 868 { |
807 int i; | 869 int i; |
808 | 870 |
809 for(i=0; i<nelem(resvd); i++) | 871 for(i=0; i<nelem(resvd); i++) |
810 reg[resvd[i]]--; | 872 reg[resvd[i]]--; |
811 | 873 |
812 for(i=D_AX; i<=D_DI; i++) | 874 for(i=D_AX; i<=D_DI; i++) |
813 if(reg[i]) | 875 if(reg[i]) |
814 yyerror("reg %R left allocated at %ux", i, regpc[i]); | 876 yyerror("reg %R left allocated at %ux", i, regpc[i]); |
| 877 for(i=D_X0; i<=D_X7; i++) |
| 878 if(reg[i]) |
| 879 yyerror("reg %R left allocated\n", i); |
815 } | 880 } |
816 | 881 |
817 int32 | 882 int32 |
818 anyregalloc(void) | 883 anyregalloc(void) |
819 { | 884 { |
820 int i, j; | 885 int i, j; |
821 | 886 |
822 for(i=D_AX; i<=D_DI; i++) { | 887 for(i=D_AX; i<=D_DI; i++) { |
823 if(reg[i] == 0) | 888 if(reg[i] == 0) |
824 goto ok; | 889 goto ok; |
825 for(j=0; j<nelem(resvd); j++) | 890 for(j=0; j<nelem(resvd); j++) |
826 if(resvd[j] == i) | 891 if(resvd[j] == i) |
827 goto ok; | 892 goto ok; |
828 return 1; | 893 return 1; |
829 ok:; | 894 ok:; |
830 } | 895 } |
| 896 for(i=D_X0; i<=D_X7; i++) |
| 897 if(reg[i]) |
| 898 return 1; |
831 return 0; | 899 return 0; |
832 } | 900 } |
833 | 901 |
834 /* | 902 /* |
835 * allocate register of type t, leave in n. | 903 * allocate register of type t, leave in n. |
836 * if o != N, o is desired fixed register. | 904 * if o != N, o is desired fixed register. |
837 * caller must regfree(n). | 905 * caller must regfree(n). |
838 */ | 906 */ |
839 void | 907 void |
840 regalloc(Node *n, Type *t, Node *o) | 908 regalloc(Node *n, Type *t, Node *o) |
841 { | 909 { |
842 int i, et; | 910 int i, et; |
843 | 911 |
844 if(t == T) | 912 if(t == T) |
845 fatal("regalloc: t nil"); | 913 fatal("regalloc: t nil"); |
846 et = simtype[t->etype]; | 914 et = simtype[t->etype]; |
847 | 915 |
848 switch(et) { | 916 switch(et) { |
| 917 case TINT64: |
| 918 case TUINT64: |
| 919 fatal("regalloc64"); |
| 920 |
849 case TINT8: | 921 case TINT8: |
850 case TUINT8: | 922 case TUINT8: |
851 case TINT16: | 923 case TINT16: |
852 case TUINT16: | 924 case TUINT16: |
853 case TINT32: | 925 case TINT32: |
854 case TUINT32: | 926 case TUINT32: |
855 case TINT64: | |
856 case TUINT64: | |
857 case TPTR32: | 927 case TPTR32: |
858 case TPTR64: | 928 case TPTR64: |
859 case TBOOL: | 929 case TBOOL: |
860 if(o != N && o->op == OREGISTER) { | 930 if(o != N && o->op == OREGISTER) { |
861 i = o->val.u.reg; | 931 i = o->val.u.reg; |
862 if(i >= D_AX && i <= D_DI) | 932 if(i >= D_AX && i <= D_DI) |
863 goto out; | 933 goto out; |
864 } | 934 } |
865 for(i=D_AX; i<=D_DI; i++) | 935 for(i=D_AX; i<=D_DI; i++) |
866 if(reg[i] == 0) | 936 if(reg[i] == 0) |
867 goto out; | 937 goto out; |
868 | 938 |
869 fprint(2, "registers allocated at\n"); | 939 fprint(2, "registers allocated at\n"); |
870 for(i=D_AX; i<=D_DI; i++) | 940 for(i=D_AX; i<=D_DI; i++) |
871 fprint(2, "\t%R\t%#lux\n", i, regpc[i]); | 941 fprint(2, "\t%R\t%#lux\n", i, regpc[i]); |
872 yyerror("out of fixed registers"); | 942 yyerror("out of fixed registers"); |
873 goto err; | 943 goto err; |
874 | 944 |
875 case TFLOAT32: | 945 case TFLOAT32: |
876 case TFLOAT64: | 946 case TFLOAT64: |
877 » » i = D_F0; | 947 » » if(!use_sse) { |
878 » » goto out; | 948 » » » i = D_F0; |
| 949 » » » goto out; |
| 950 » » } |
| 951 » » if(o != N && o->op == OREGISTER) { |
| 952 » » » i = o->val.u.reg; |
| 953 » » » if(i >= D_X0 && i <= D_X7) |
| 954 » » » » goto out; |
| 955 » » } |
| 956 » » for(i=D_X0; i<=D_X7; i++) |
| 957 » » » if(reg[i] == 0) |
| 958 » » » » goto out; |
| 959 » » fprint(2, "registers allocated at\n"); |
| 960 » » for(i=D_X0; i<=D_X7; i++) |
| 961 » » » fprint(2, "\t%R\t%#lux\n", i, regpc[i]); |
| 962 » » fatal("out of floating registers"); |
879 } | 963 } |
880 yyerror("regalloc: unknown type %T", t); | 964 yyerror("regalloc: unknown type %T", t); |
881 | 965 |
882 err: | 966 err: |
883 nodreg(n, t, 0); | 967 nodreg(n, t, 0); |
884 return; | 968 return; |
885 | 969 |
886 out: | 970 out: |
887 if (i == D_SP) | 971 if (i == D_SP) |
888 print("alloc SP\n"); | 972 print("alloc SP\n"); |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1172 void | 1256 void |
1173 memname(Node *n, Type *t) | 1257 memname(Node *n, Type *t) |
1174 { | 1258 { |
1175 tempname(n, t); | 1259 tempname(n, t); |
1176 strcpy(namebuf, n->sym->name); | 1260 strcpy(namebuf, n->sym->name); |
1177 namebuf[0] = '.'; // keep optimizer from registerizing | 1261 namebuf[0] = '.'; // keep optimizer from registerizing |
1178 n->sym = lookup(namebuf); | 1262 n->sym = lookup(namebuf); |
1179 n->orig->sym = n->sym; | 1263 n->orig->sym = n->sym; |
1180 } | 1264 } |
1181 | 1265 |
| 1266 static void floatmove(Node *f, Node *t); |
| 1267 static void floatmove_387(Node *f, Node *t); |
| 1268 static void floatmove_sse(Node *f, Node *t); |
| 1269 |
1182 void | 1270 void |
1183 gmove(Node *f, Node *t) | 1271 gmove(Node *f, Node *t) |
1184 { | 1272 { |
1185 int a, ft, tt; | 1273 int a, ft, tt; |
1186 Type *cvt; | 1274 Type *cvt; |
1187 » Node r1, r2, t1, t2, flo, fhi, tlo, thi, con, f0, f1, ax, dx, cx; | 1275 » Node r1, r2, flo, fhi, tlo, thi, con; |
1188 » Prog *p1, *p2, *p3; | |
1189 | 1276 |
1190 if(debug['M']) | 1277 if(debug['M']) |
1191 print("gmove %N -> %N\n", f, t); | 1278 print("gmove %N -> %N\n", f, t); |
1192 | 1279 |
1193 ft = simsimtype(f->type); | 1280 ft = simsimtype(f->type); |
1194 tt = simsimtype(t->type); | 1281 tt = simsimtype(t->type); |
1195 cvt = t->type; | 1282 cvt = t->type; |
1196 | 1283 » |
1197 if(iscomplex[ft] || iscomplex[tt]) { | 1284 if(iscomplex[ft] || iscomplex[tt]) { |
1198 complexmove(f, t); | 1285 complexmove(f, t); |
| 1286 return; |
| 1287 } |
| 1288 if(isfloat[ft] || isfloat[tt]) { |
| 1289 floatmove(f, t); |
1199 return; | 1290 return; |
1200 } | 1291 } |
1201 | 1292 |
1202 // cannot have two integer memory operands; | 1293 // cannot have two integer memory operands; |
1203 // except 64-bit, which always copies via registers anyway. | 1294 // except 64-bit, which always copies via registers anyway. |
1204 if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f
) && ismem(t)) | 1295 if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f
) && ismem(t)) |
1205 goto hard; | 1296 goto hard; |
1206 | 1297 |
1207 // convert constant to desired type | 1298 // convert constant to desired type |
1208 if(f->op == OLITERAL) { | 1299 if(f->op == OLITERAL) { |
1209 » » if(tt == TFLOAT32) | 1300 » » convconst(&con, t->type, &f->val); |
1210 » » » convconst(&con, types[TFLOAT64], &f->val); | |
1211 » » else | |
1212 » » » convconst(&con, t->type, &f->val); | |
1213 f = &con; | 1301 f = &con; |
1214 ft = simsimtype(con.type); | 1302 ft = simsimtype(con.type); |
1215 | |
1216 // some constants can't move directly to memory. | |
1217 if(ismem(t)) { | |
1218 // float constants come from memory. | |
1219 if(isfloat[tt]) | |
1220 goto hard; | |
1221 } | |
1222 } | 1303 } |
1223 | 1304 |
1224 // value -> value copy, only one memory operand. | 1305 // value -> value copy, only one memory operand. |
1225 // figure out the instruction to use. | 1306 // figure out the instruction to use. |
1226 // break out of switch for one-instruction gins. | 1307 // break out of switch for one-instruction gins. |
1227 // goto rdst for "destination must be register". | 1308 // goto rdst for "destination must be register". |
1228 // goto hard for "convert to cvt type first". | 1309 // goto hard for "convert to cvt type first". |
1229 // otherwise handle and return. | 1310 // otherwise handle and return. |
1230 | 1311 |
1231 switch(CASE(ft, tt)) { | 1312 switch(CASE(ft, tt)) { |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1387 splitclean(); | 1468 splitclean(); |
1388 return; | 1469 return; |
1389 | 1470 |
1390 case CASE(TUINT32, TINT64): // zero extend uint32 | 1471 case CASE(TUINT32, TINT64): // zero extend uint32 |
1391 case CASE(TUINT32, TUINT64): | 1472 case CASE(TUINT32, TUINT64): |
1392 split64(t, &tlo, &thi); | 1473 split64(t, &tlo, &thi); |
1393 gmove(f, &tlo); | 1474 gmove(f, &tlo); |
1394 gins(AMOVL, ncon(0), &thi); | 1475 gins(AMOVL, ncon(0), &thi); |
1395 splitclean(); | 1476 splitclean(); |
1396 return; | 1477 return; |
| 1478 } |
| 1479 |
| 1480 gins(a, f, t); |
| 1481 return; |
| 1482 |
| 1483 rsrc: |
| 1484 // requires register source |
| 1485 regalloc(&r1, f->type, t); |
| 1486 gmove(f, &r1); |
| 1487 gins(a, &r1, t); |
| 1488 regfree(&r1); |
| 1489 return; |
| 1490 |
| 1491 rdst: |
| 1492 // requires register destination |
| 1493 regalloc(&r1, t->type, t); |
| 1494 gins(a, f, &r1); |
| 1495 gmove(&r1, t); |
| 1496 regfree(&r1); |
| 1497 return; |
| 1498 |
| 1499 hard: |
| 1500 // requires register intermediate |
| 1501 regalloc(&r1, cvt, t); |
| 1502 gmove(f, &r1); |
| 1503 gmove(&r1, t); |
| 1504 regfree(&r1); |
| 1505 return; |
| 1506 |
| 1507 fatal: |
| 1508 // should not happen |
| 1509 fatal("gmove %N -> %N", f, t); |
| 1510 } |
| 1511 |
| 1512 static void |
| 1513 floatmove(Node *f, Node *t) |
| 1514 { |
| 1515 Node r1, r2, t1, t2, tlo, thi, con, f0, f1, ax, dx, cx; |
| 1516 Type *cvt; |
| 1517 int a, ft, tt; |
| 1518 Prog *p1, *p2, *p3; |
| 1519 |
| 1520 ft = simsimtype(f->type); |
| 1521 tt = simsimtype(t->type); |
| 1522 cvt = t->type; |
| 1523 |
| 1524 // cannot have two floating point memory operands. |
| 1525 if(isfloat[ft] && isfloat[tt] && ismem(f) && ismem(t)) |
| 1526 goto hard; |
| 1527 |
| 1528 // convert constant to desired type |
| 1529 if(f->op == OLITERAL) { |
| 1530 convconst(&con, t->type, &f->val); |
| 1531 f = &con; |
| 1532 ft = simsimtype(con.type); |
| 1533 |
| 1534 // some constants can't move directly to memory. |
| 1535 if(ismem(t)) { |
| 1536 // float constants come from memory. |
| 1537 if(isfloat[tt]) |
| 1538 goto hard; |
| 1539 } |
| 1540 } |
| 1541 |
| 1542 // value -> value copy, only one memory operand. |
| 1543 // figure out the instruction to use. |
| 1544 // break out of switch for one-instruction gins. |
| 1545 // goto rdst for "destination must be register". |
| 1546 // goto hard for "convert to cvt type first". |
| 1547 // otherwise handle and return. |
| 1548 |
| 1549 switch(CASE(ft, tt)) { |
| 1550 default: |
| 1551 if(use_sse) |
| 1552 floatmove_sse(f, t); |
| 1553 else |
| 1554 floatmove_387(f, t); |
| 1555 return; |
| 1556 |
| 1557 // float to very long integer. |
| 1558 case CASE(TFLOAT32, TINT64): |
| 1559 case CASE(TFLOAT64, TINT64): |
| 1560 if(f->op == OREGISTER) { |
| 1561 cvt = f->type; |
| 1562 goto hardmem; |
| 1563 } |
| 1564 nodreg(&r1, types[ft], D_F0); |
| 1565 if(ft == TFLOAT32) |
| 1566 gins(AFMOVF, f, &r1); |
| 1567 else |
| 1568 gins(AFMOVD, f, &r1); |
| 1569 |
| 1570 // set round to zero mode during conversion |
| 1571 memname(&t1, types[TUINT16]); |
| 1572 memname(&t2, types[TUINT16]); |
| 1573 gins(AFSTCW, N, &t1); |
| 1574 gins(AMOVW, ncon(0xf7f), &t2); |
| 1575 gins(AFLDCW, &t2, N); |
| 1576 if(tt == TINT16) |
| 1577 gins(AFMOVWP, &r1, t); |
| 1578 else if(tt == TINT32) |
| 1579 gins(AFMOVLP, &r1, t); |
| 1580 else |
| 1581 gins(AFMOVVP, &r1, t); |
| 1582 gins(AFLDCW, &t1, N); |
| 1583 return; |
| 1584 |
| 1585 case CASE(TFLOAT32, TUINT64): |
| 1586 case CASE(TFLOAT64, TUINT64): |
| 1587 if(!ismem(f)) { |
| 1588 cvt = f->type; |
| 1589 goto hardmem; |
| 1590 } |
| 1591 bignodes(); |
| 1592 nodreg(&f0, types[ft], D_F0); |
| 1593 nodreg(&f1, types[ft], D_F0 + 1); |
| 1594 nodreg(&ax, types[TUINT16], D_AX); |
| 1595 |
| 1596 if(ft == TFLOAT32) |
| 1597 gins(AFMOVF, f, &f0); |
| 1598 else |
| 1599 gins(AFMOVD, f, &f0); |
| 1600 |
| 1601 // if 0 > v { answer = 0 } |
| 1602 gins(AFMOVD, &zerof, &f0); |
| 1603 gins(AFUCOMIP, &f0, &f1); |
| 1604 p1 = gbranch(optoas(OGT, types[tt]), T, 0); |
| 1605 // if 1<<64 <= v { answer = 0 too } |
| 1606 gins(AFMOVD, &two64f, &f0); |
| 1607 gins(AFUCOMIP, &f0, &f1); |
| 1608 p2 = gbranch(optoas(OGT, types[tt]), T, 0); |
| 1609 patch(p1, pc); |
| 1610 gins(AFMOVVP, &f0, t); // don't care about t, but will pop the
stack |
| 1611 split64(t, &tlo, &thi); |
| 1612 gins(AMOVL, ncon(0), &tlo); |
| 1613 gins(AMOVL, ncon(0), &thi); |
| 1614 splitclean(); |
| 1615 p1 = gbranch(AJMP, T, 0); |
| 1616 patch(p2, pc); |
| 1617 |
| 1618 // in range; algorithm is: |
| 1619 // if small enough, use native float64 -> int64 conversion. |
| 1620 // otherwise, subtract 2^63, convert, and add it back. |
| 1621 |
| 1622 // set round to zero mode during conversion |
| 1623 memname(&t1, types[TUINT16]); |
| 1624 memname(&t2, types[TUINT16]); |
| 1625 gins(AFSTCW, N, &t1); |
| 1626 gins(AMOVW, ncon(0xf7f), &t2); |
| 1627 gins(AFLDCW, &t2, N); |
| 1628 |
| 1629 // actual work |
| 1630 gins(AFMOVD, &two63f, &f0); |
| 1631 gins(AFUCOMIP, &f0, &f1); |
| 1632 p2 = gbranch(optoas(OLE, types[tt]), T, 0); |
| 1633 gins(AFMOVVP, &f0, t); |
| 1634 p3 = gbranch(AJMP, T, 0); |
| 1635 patch(p2, pc); |
| 1636 gins(AFMOVD, &two63f, &f0); |
| 1637 gins(AFSUBDP, &f0, &f1); |
| 1638 gins(AFMOVVP, &f0, t); |
| 1639 split64(t, &tlo, &thi); |
| 1640 gins(AXORL, ncon(0x80000000), &thi); // + 2^63 |
| 1641 patch(p3, pc); |
| 1642 splitclean(); |
| 1643 // restore rounding mode |
| 1644 gins(AFLDCW, &t1, N); |
| 1645 |
| 1646 patch(p1, pc); |
| 1647 return; |
| 1648 |
| 1649 /* |
| 1650 * integer to float |
| 1651 */ |
| 1652 case CASE(TINT64, TFLOAT32): |
| 1653 case CASE(TINT64, TFLOAT64): |
| 1654 if(t->op == OREGISTER) |
| 1655 goto hardmem; |
| 1656 nodreg(&f0, t->type, D_F0); |
| 1657 gins(AFMOVV, f, &f0); |
| 1658 if(tt == TFLOAT32) |
| 1659 gins(AFMOVFP, &f0, t); |
| 1660 else |
| 1661 gins(AFMOVDP, &f0, t); |
| 1662 return; |
| 1663 |
| 1664 case CASE(TUINT64, TFLOAT32): |
| 1665 case CASE(TUINT64, TFLOAT64): |
| 1666 // algorithm is: |
| 1667 // if small enough, use native int64 -> float64 conversion. |
| 1668 // otherwise, halve (rounding to odd?), convert, and double
. |
| 1669 nodreg(&ax, types[TUINT32], D_AX); |
| 1670 nodreg(&dx, types[TUINT32], D_DX); |
| 1671 nodreg(&cx, types[TUINT32], D_CX); |
| 1672 tempname(&t1, f->type); |
| 1673 split64(&t1, &tlo, &thi); |
| 1674 gmove(f, &t1); |
| 1675 gins(ACMPL, &thi, ncon(0)); |
| 1676 p1 = gbranch(AJLT, T, 0); |
| 1677 // native |
| 1678 t1.type = types[TINT64]; |
| 1679 nodreg(&r1, types[tt], D_F0); |
| 1680 gins(AFMOVV, &t1, &r1); |
| 1681 if(tt == TFLOAT32) |
| 1682 gins(AFMOVFP, &r1, t); |
| 1683 else |
| 1684 gins(AFMOVDP, &r1, t); |
| 1685 p2 = gbranch(AJMP, T, 0); |
| 1686 // simulated |
| 1687 patch(p1, pc); |
| 1688 gmove(&tlo, &ax); |
| 1689 gmove(&thi, &dx); |
| 1690 p1 = gins(ASHRL, ncon(1), &ax); |
| 1691 p1->from.index = D_DX; // double-width shift DX -> AX |
| 1692 p1->from.scale = 0; |
| 1693 gins(AMOVL, ncon(0), &cx); |
| 1694 gins(ASETCC, N, &cx); |
| 1695 gins(AORL, &cx, &ax); |
| 1696 gins(ASHRL, ncon(1), &dx); |
| 1697 gmove(&dx, &thi); |
| 1698 gmove(&ax, &tlo); |
| 1699 nodreg(&r1, types[tt], D_F0); |
| 1700 nodreg(&r2, types[tt], D_F0 + 1); |
| 1701 gins(AFMOVV, &t1, &r1); |
| 1702 gins(AFMOVD, &r1, &r1); |
| 1703 gins(AFADDDP, &r1, &r2); |
| 1704 if(tt == TFLOAT32) |
| 1705 gins(AFMOVFP, &r1, t); |
| 1706 else |
| 1707 gins(AFMOVDP, &r1, t); |
| 1708 patch(p2, pc); |
| 1709 splitclean(); |
| 1710 return; |
| 1711 } |
| 1712 |
| 1713 gins(a, f, t); |
| 1714 return; |
| 1715 |
| 1716 hard: |
| 1717 // requires register intermediate |
| 1718 regalloc(&r1, cvt, t); |
| 1719 gmove(f, &r1); |
| 1720 gmove(&r1, t); |
| 1721 regfree(&r1); |
| 1722 return; |
| 1723 |
| 1724 hardmem: |
| 1725 // requires memory intermediate |
| 1726 tempname(&r1, cvt); |
| 1727 gmove(f, &r1); |
| 1728 gmove(&r1, t); |
| 1729 return; |
| 1730 } |
| 1731 |
| 1732 static void |
| 1733 floatmove_387(Node *f, Node *t) |
| 1734 { |
| 1735 Node r1, t1, t2; |
| 1736 Type *cvt; |
| 1737 Prog *p1, *p2, *p3; |
| 1738 int a, ft, tt; |
| 1739 |
| 1740 ft = simsimtype(f->type); |
| 1741 tt = simsimtype(t->type); |
| 1742 cvt = t->type; |
| 1743 |
| 1744 switch(CASE(ft, tt)) { |
| 1745 default: |
| 1746 goto fatal; |
1397 | 1747 |
1398 /* | 1748 /* |
1399 * float to integer | 1749 * float to integer |
1400 */ | 1750 */ |
1401 case CASE(TFLOAT32, TINT16): | 1751 case CASE(TFLOAT32, TINT16): |
1402 case CASE(TFLOAT32, TINT32): | 1752 case CASE(TFLOAT32, TINT32): |
1403 case CASE(TFLOAT32, TINT64): | 1753 case CASE(TFLOAT32, TINT64): |
1404 case CASE(TFLOAT64, TINT16): | 1754 case CASE(TFLOAT64, TINT16): |
1405 case CASE(TFLOAT64, TINT32): | 1755 case CASE(TFLOAT64, TINT32): |
1406 case CASE(TFLOAT64, TINT64): | 1756 case CASE(TFLOAT64, TINT64): |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1466 gins(AMOVL, ncon(0), &t1); | 1816 gins(AMOVL, ncon(0), &t1); |
1467 patch(p1, pc); | 1817 patch(p1, pc); |
1468 gmove(&t1, t); | 1818 gmove(&t1, t); |
1469 break; | 1819 break; |
1470 } | 1820 } |
1471 return; | 1821 return; |
1472 | 1822 |
1473 case CASE(TFLOAT32, TUINT32): | 1823 case CASE(TFLOAT32, TUINT32): |
1474 case CASE(TFLOAT64, TUINT32): | 1824 case CASE(TFLOAT64, TUINT32): |
1475 // convert via int64. | 1825 // convert via int64. |
1476 » » tempname(&t1, types[TINT64]); | 1826 » » cvt = types[TINT64]; |
1477 » » gmove(f, &t1); | 1827 » » goto hardmem; |
1478 » » split64(&t1, &tlo, &thi); | |
1479 » » gins(ACMPL, &thi, ncon(0)); | |
1480 » » p1 = gbranch(AJEQ, T, +1); | |
1481 » » gins(AMOVL, ncon(0), &tlo); | |
1482 » » patch(p1, pc); | |
1483 » » gmove(&tlo, t); | |
1484 » » splitclean(); | |
1485 » » return; | |
1486 | |
1487 » case CASE(TFLOAT32, TUINT64): | |
1488 » case CASE(TFLOAT64, TUINT64): | |
1489 » » bignodes(); | |
1490 » » nodreg(&f0, types[ft], D_F0); | |
1491 » » nodreg(&f1, types[ft], D_F0 + 1); | |
1492 » » nodreg(&ax, types[TUINT16], D_AX); | |
1493 | |
1494 » » gmove(f, &f0); | |
1495 | |
1496 » » // if 0 > v { answer = 0 } | |
1497 » » gmove(&zerof, &f0); | |
1498 » » gins(AFUCOMIP, &f0, &f1); | |
1499 » » p1 = gbranch(optoas(OGT, types[tt]), T, 0); | |
1500 » » // if 1<<64 <= v { answer = 0 too } | |
1501 » » gmove(&two64f, &f0); | |
1502 » » gins(AFUCOMIP, &f0, &f1); | |
1503 » » p2 = gbranch(optoas(OGT, types[tt]), T, 0); | |
1504 » » patch(p1, pc); | |
1505 » » gins(AFMOVVP, &f0, t);» // don't care about t, but will pop the
stack | |
1506 » » split64(t, &tlo, &thi); | |
1507 » » gins(AMOVL, ncon(0), &tlo); | |
1508 » » gins(AMOVL, ncon(0), &thi); | |
1509 » » splitclean(); | |
1510 » » p1 = gbranch(AJMP, T, 0); | |
1511 » » patch(p2, pc); | |
1512 | |
1513 » » // in range; algorithm is: | |
1514 » » //» if small enough, use native float64 -> int64 conversion. | |
1515 » » //» otherwise, subtract 2^63, convert, and add it back. | |
1516 | |
1517 » » // set round to zero mode during conversion | |
1518 » » memname(&t1, types[TUINT16]); | |
1519 » » memname(&t2, types[TUINT16]); | |
1520 » » gins(AFSTCW, N, &t1); | |
1521 » » gins(AMOVW, ncon(0xf7f), &t2); | |
1522 » » gins(AFLDCW, &t2, N); | |
1523 | |
1524 » » // actual work | |
1525 » » gmove(&two63f, &f0); | |
1526 » » gins(AFUCOMIP, &f0, &f1); | |
1527 » » p2 = gbranch(optoas(OLE, types[tt]), T, 0); | |
1528 » » gins(AFMOVVP, &f0, t); | |
1529 » » p3 = gbranch(AJMP, T, 0); | |
1530 » » patch(p2, pc); | |
1531 » » gmove(&two63f, &f0); | |
1532 » » gins(AFSUBDP, &f0, &f1); | |
1533 » » gins(AFMOVVP, &f0, t); | |
1534 » » split64(t, &tlo, &thi); | |
1535 » » gins(AXORL, ncon(0x80000000), &thi);» // + 2^63 | |
1536 » » patch(p3, pc); | |
1537 » » splitclean(); | |
1538 » » // restore rounding mode | |
1539 » » gins(AFLDCW, &t1, N); | |
1540 | |
1541 » » patch(p1, pc); | |
1542 » » return; | |
1543 | 1828 |
1544 /* | 1829 /* |
1545 * integer to float | 1830 * integer to float |
1546 */ | 1831 */ |
1547 case CASE(TINT16, TFLOAT32): | 1832 case CASE(TINT16, TFLOAT32): |
1548 case CASE(TINT16, TFLOAT64): | 1833 case CASE(TINT16, TFLOAT64): |
1549 case CASE(TINT32, TFLOAT32): | 1834 case CASE(TINT32, TFLOAT32): |
1550 case CASE(TINT32, TFLOAT64): | 1835 case CASE(TINT32, TFLOAT64): |
1551 case CASE(TINT64, TFLOAT32): | 1836 case CASE(TINT64, TFLOAT32): |
1552 case CASE(TINT64, TFLOAT64): | 1837 case CASE(TINT64, TFLOAT64): |
(...skipping 24 matching lines...) Expand all Loading... |
1577 case CASE(TUINT8, TFLOAT64): | 1862 case CASE(TUINT8, TFLOAT64): |
1578 // convert via int32 memory | 1863 // convert via int32 memory |
1579 cvt = types[TINT32]; | 1864 cvt = types[TINT32]; |
1580 goto hardmem; | 1865 goto hardmem; |
1581 | 1866 |
1582 case CASE(TUINT32, TFLOAT32): | 1867 case CASE(TUINT32, TFLOAT32): |
1583 case CASE(TUINT32, TFLOAT64): | 1868 case CASE(TUINT32, TFLOAT64): |
1584 // convert via int64 memory | 1869 // convert via int64 memory |
1585 cvt = types[TINT64]; | 1870 cvt = types[TINT64]; |
1586 goto hardmem; | 1871 goto hardmem; |
1587 | |
1588 case CASE(TUINT64, TFLOAT32): | |
1589 case CASE(TUINT64, TFLOAT64): | |
1590 // algorithm is: | |
1591 // if small enough, use native int64 -> uint64 conversion. | |
1592 // otherwise, halve (rounding to odd?), convert, and double
. | |
1593 nodreg(&ax, types[TUINT32], D_AX); | |
1594 nodreg(&dx, types[TUINT32], D_DX); | |
1595 nodreg(&cx, types[TUINT32], D_CX); | |
1596 tempname(&t1, f->type); | |
1597 split64(&t1, &tlo, &thi); | |
1598 gmove(f, &t1); | |
1599 gins(ACMPL, &thi, ncon(0)); | |
1600 p1 = gbranch(AJLT, T, 0); | |
1601 // native | |
1602 t1.type = types[TINT64]; | |
1603 gmove(&t1, t); | |
1604 p2 = gbranch(AJMP, T, 0); | |
1605 // simulated | |
1606 patch(p1, pc); | |
1607 gmove(&tlo, &ax); | |
1608 gmove(&thi, &dx); | |
1609 p1 = gins(ASHRL, ncon(1), &ax); | |
1610 p1->from.index = D_DX; // double-width shift DX -> AX | |
1611 p1->from.scale = 0; | |
1612 gins(AMOVL, ncon(0), &cx); | |
1613 gins(ASETCC, N, &cx); | |
1614 gins(AORL, &cx, &ax); | |
1615 gins(ASHRL, ncon(1), &dx); | |
1616 gmove(&dx, &thi); | |
1617 gmove(&ax, &tlo); | |
1618 nodreg(&r1, types[tt], D_F0); | |
1619 nodreg(&r2, types[tt], D_F0 + 1); | |
1620 gmove(&t1, &r1); // t1.type is TINT64 now, set above | |
1621 gins(AFMOVD, &r1, &r1); | |
1622 gins(AFADDDP, &r1, &r2); | |
1623 gmove(&r1, t); | |
1624 patch(p2, pc); | |
1625 splitclean(); | |
1626 return; | |
1627 | 1872 |
1628 /* | 1873 /* |
1629 * float to float | 1874 * float to float |
1630 */ | 1875 */ |
1631 case CASE(TFLOAT32, TFLOAT32): | 1876 case CASE(TFLOAT32, TFLOAT32): |
1632 case CASE(TFLOAT64, TFLOAT64): | 1877 case CASE(TFLOAT64, TFLOAT64): |
1633 // The way the code generator uses floating-point | 1878 // The way the code generator uses floating-point |
1634 // registers, a move from F0 to F0 is intended as a no-op. | 1879 // registers, a move from F0 to F0 is intended as a no-op. |
1635 // On the x86, it's not: it pushes a second copy of F0 | 1880 // On the x86, it's not: it pushes a second copy of F0 |
1636 // on the floating point stack. So toss it away here. | 1881 // on the floating point stack. So toss it away here. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1681 if(f->op == OREGISTER) | 1926 if(f->op == OREGISTER) |
1682 gins(AFMOVFP, f, t); | 1927 gins(AFMOVFP, f, t); |
1683 else | 1928 else |
1684 gins(AFMOVD, f, t); | 1929 gins(AFMOVD, f, t); |
1685 return; | 1930 return; |
1686 } | 1931 } |
1687 | 1932 |
1688 gins(a, f, t); | 1933 gins(a, f, t); |
1689 return; | 1934 return; |
1690 | 1935 |
1691 rsrc: | 1936 hard: |
1692 » // requires register source | 1937 » // requires register intermediate |
1693 » regalloc(&r1, f->type, t); | 1938 » regalloc(&r1, cvt, t); |
1694 gmove(f, &r1); | 1939 gmove(f, &r1); |
1695 » gins(a, &r1, t); | 1940 » gmove(&r1, t); |
1696 regfree(&r1); | 1941 regfree(&r1); |
| 1942 return; |
| 1943 |
| 1944 hardmem: |
| 1945 // requires memory intermediate |
| 1946 tempname(&r1, cvt); |
| 1947 gmove(f, &r1); |
| 1948 gmove(&r1, t); |
| 1949 return; |
| 1950 |
| 1951 fatal: |
| 1952 // should not happen |
| 1953 fatal("gmove %lN -> %lN", f, t); |
| 1954 return; |
| 1955 } |
| 1956 |
| 1957 static void |
| 1958 floatmove_sse(Node *f, Node *t) |
| 1959 { |
| 1960 Node r1; |
| 1961 Type *cvt; |
| 1962 int a, ft, tt; |
| 1963 |
| 1964 ft = simsimtype(f->type); |
| 1965 tt = simsimtype(t->type); |
| 1966 |
| 1967 switch(CASE(ft, tt)) { |
| 1968 default: |
| 1969 // should not happen |
| 1970 fatal("gmove %N -> %N", f, t); |
| 1971 return; |
| 1972 /* |
| 1973 * float to integer |
| 1974 */ |
| 1975 case CASE(TFLOAT32, TINT16): |
| 1976 case CASE(TFLOAT32, TINT8): |
| 1977 case CASE(TFLOAT32, TUINT16): |
| 1978 case CASE(TFLOAT32, TUINT8): |
| 1979 case CASE(TFLOAT64, TINT16): |
| 1980 case CASE(TFLOAT64, TINT8): |
| 1981 case CASE(TFLOAT64, TUINT16): |
| 1982 case CASE(TFLOAT64, TUINT8): |
| 1983 // convert via int32. |
| 1984 cvt = types[TINT32]; |
| 1985 goto hard; |
| 1986 |
| 1987 case CASE(TFLOAT32, TUINT32): |
| 1988 case CASE(TFLOAT64, TUINT32): |
| 1989 // convert via int64. |
| 1990 cvt = types[TINT64]; |
| 1991 goto hardmem; |
| 1992 |
| 1993 case CASE(TFLOAT32, TINT32): |
| 1994 a = ACVTTSS2SL; |
| 1995 goto rdst; |
| 1996 |
| 1997 case CASE(TFLOAT64, TINT32): |
| 1998 a = ACVTTSD2SL; |
| 1999 goto rdst; |
| 2000 |
| 2001 /* |
| 2002 * integer to float |
| 2003 */ |
| 2004 case CASE(TINT8, TFLOAT32): |
| 2005 case CASE(TINT8, TFLOAT64): |
| 2006 case CASE(TINT16, TFLOAT32): |
| 2007 case CASE(TINT16, TFLOAT64): |
| 2008 case CASE(TUINT16, TFLOAT32): |
| 2009 case CASE(TUINT16, TFLOAT64): |
| 2010 case CASE(TUINT8, TFLOAT32): |
| 2011 case CASE(TUINT8, TFLOAT64): |
| 2012 // convert via int32 memory |
| 2013 cvt = types[TINT32]; |
| 2014 goto hard; |
| 2015 |
| 2016 case CASE(TUINT32, TFLOAT32): |
| 2017 case CASE(TUINT32, TFLOAT64): |
| 2018 // convert via int64 memory |
| 2019 cvt = types[TINT64]; |
| 2020 goto hardmem; |
| 2021 |
| 2022 case CASE(TINT32, TFLOAT32): |
| 2023 a = ACVTSL2SS; |
| 2024 goto rdst; |
| 2025 |
| 2026 case CASE(TINT32, TFLOAT64): |
| 2027 a = ACVTSL2SD; |
| 2028 goto rdst; |
| 2029 |
| 2030 /* |
| 2031 * float to float |
| 2032 */ |
| 2033 case CASE(TFLOAT32, TFLOAT32): |
| 2034 a = AMOVSS; |
| 2035 break; |
| 2036 |
| 2037 case CASE(TFLOAT64, TFLOAT64): |
| 2038 a = AMOVSD; |
| 2039 break; |
| 2040 |
| 2041 case CASE(TFLOAT32, TFLOAT64): |
| 2042 a = ACVTSS2SD; |
| 2043 goto rdst; |
| 2044 |
| 2045 case CASE(TFLOAT64, TFLOAT32): |
| 2046 a = ACVTSD2SS; |
| 2047 goto rdst; |
| 2048 } |
| 2049 |
| 2050 gins(a, f, t); |
| 2051 return; |
| 2052 |
| 2053 hard: |
| 2054 // requires register intermediate |
| 2055 regalloc(&r1, cvt, t); |
| 2056 gmove(f, &r1); |
| 2057 gmove(&r1, t); |
| 2058 regfree(&r1); |
| 2059 return; |
| 2060 |
| 2061 hardmem: |
| 2062 // requires memory intermediate |
| 2063 tempname(&r1, cvt); |
| 2064 gmove(f, &r1); |
| 2065 gmove(&r1, t); |
1697 return; | 2066 return; |
1698 | 2067 |
1699 rdst: | 2068 rdst: |
1700 // requires register destination | 2069 // requires register destination |
1701 regalloc(&r1, t->type, t); | 2070 regalloc(&r1, t->type, t); |
1702 gins(a, f, &r1); | 2071 gins(a, f, &r1); |
1703 gmove(&r1, t); | 2072 gmove(&r1, t); |
1704 regfree(&r1); | 2073 regfree(&r1); |
1705 return; | 2074 return; |
1706 | |
1707 hard: | |
1708 // requires register intermediate | |
1709 regalloc(&r1, cvt, t); | |
1710 gmove(f, &r1); | |
1711 gmove(&r1, t); | |
1712 regfree(&r1); | |
1713 return; | |
1714 | |
1715 hardmem: | |
1716 // requires memory intermediate | |
1717 tempname(&r1, cvt); | |
1718 gmove(f, &r1); | |
1719 gmove(&r1, t); | |
1720 return; | |
1721 | |
1722 fatal: | |
1723 // should not happen | |
1724 fatal("gmove %N -> %N", f, t); | |
1725 } | 2075 } |
1726 | 2076 |
1727 int | 2077 int |
1728 samaddr(Node *f, Node *t) | 2078 samaddr(Node *f, Node *t) |
1729 { | 2079 { |
1730 | 2080 |
1731 if(f->op != t->op) | 2081 if(f->op != t->op) |
1732 return 0; | 2082 return 0; |
1733 | 2083 |
1734 switch(f->op) { | 2084 switch(f->op) { |
(...skipping 10 matching lines...) Expand all Loading... |
1745 */ | 2095 */ |
1746 Prog* | 2096 Prog* |
1747 gins(int as, Node *f, Node *t) | 2097 gins(int as, Node *f, Node *t) |
1748 { | 2098 { |
1749 Prog *p; | 2099 Prog *p; |
1750 Addr af, at; | 2100 Addr af, at; |
1751 int w; | 2101 int w; |
1752 | 2102 |
1753 if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER) | 2103 if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER) |
1754 fatal("gins MOVF reg, reg"); | 2104 fatal("gins MOVF reg, reg"); |
| 2105 if(as == ACVTSD2SS && f && f->op == OLITERAL) |
| 2106 fatal("gins CVTSD2SS const"); |
| 2107 if(as == AMOVSD && t && t->op == OREGISTER && t->val.u.reg == D_F0) |
| 2108 fatal("gins MOVSD into F0"); |
1755 | 2109 |
1756 switch(as) { | 2110 switch(as) { |
1757 case AMOVB: | 2111 case AMOVB: |
1758 case AMOVW: | 2112 case AMOVW: |
1759 case AMOVL: | 2113 case AMOVL: |
1760 if(f != N && t != N && samaddr(f, t)) | 2114 if(f != N && t != N && samaddr(f, t)) |
1761 return nil; | 2115 return nil; |
1762 break; | 2116 break; |
1763 ········ | 2117 ········ |
1764 case ALEAL: | 2118 case ALEAL: |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2048 | 2402 |
2049 int | 2403 int |
2050 sudoaddable(int as, Node *n, Addr *a) | 2404 sudoaddable(int as, Node *n, Addr *a) |
2051 { | 2405 { |
2052 USED(as); | 2406 USED(as); |
2053 USED(n); | 2407 USED(n); |
2054 USED(a); | 2408 USED(a); |
2055 | 2409 |
2056 return 0; | 2410 return 0; |
2057 } | 2411 } |
LEFT | RIGHT |