| @@ -23,7 +23,7 @@ · 22 unmodified lines |
| 23 | 23 | #ifdef TARGET_DEFS_ONLY |
| 24 | 24 | |
| 25 | 25 | /* number of available registers */ |
| 26 | | −#define NB_REGS 5 |
| 26 | +#define NB_REGS 6 |
| 27 | 27 | #define NB_ASM_REGS 8 |
| 28 | 28 | |
| 29 | 29 | /* a register can belong to several classes. The classes must be |
| @@ -39,10 +39,12 @@ · 9 unmodified lines |
| 39 | 39 | #define RC_R10 0x0400 |
| 40 | 40 | #define RC_R11 0x0800 |
| 41 | 41 | #define RC_XMM0 0x0020 |
| 42 | | −#define RC_ST0 0x0040 /* only for long double */ |
| 42 | +#define RC_XMM1 0x0040 |
| 43 | +#define RC_ST0 0x0080 /* only for long double */ |
| 43 | 44 | #define RC_IRET RC_RAX /* function return: integer register */ |
| 44 | 45 | #define RC_LRET RC_RDX /* function return: second integer register */ |
| 45 | 46 | #define RC_FRET RC_XMM0 /* function return: float register */ |
| 47 | +#define RC_QRET RC_XMM1 /* function return: second float register */ |
| 46 | 48 | |
| 47 | 49 | /* pretty names for the registers */ |
| 48 | 50 | enum { |
| @@ -50,7 +52,8 @@ enum { · 1 unmodified line |
| 50 | 52 | TREG_RCX = 1, |
| 51 | 53 | TREG_RDX = 2, |
| 52 | 54 | TREG_XMM0 = 3, |
| 53 | | − TREG_ST0 = 4, |
| 55 | + TREG_XMM1 = 4, |
| 56 | + TREG_ST0 = 5, |
| 54 | 57 | |
| 55 | 58 | TREG_RSI = 6, |
| 56 | 59 | TREG_RDI = 7, |
| @@ -70,6 +73,7 @@ enum { · 13 unmodified lines |
| 70 | 73 | #define REG_IRET TREG_RAX /* single word int return register */ |
| 71 | 74 | #define REG_LRET TREG_RDX /* second word return register (for long long) */ |
| 72 | 75 | #define REG_FRET TREG_XMM0 /* float return register */ |
| 76 | +#define REG_QRET TREG_XMM1 /* second float return register */ |
| 73 | 77 | |
| 74 | 78 | /* defined if function parameters must be evaluated in reverse order */ |
| 75 | 79 | #define INVERT_FUNC_PARAMS |
| @@ -108,6 +112,7 @@ ST_DATA const int reg_classes[NB_REGS+7] = { · 32 unmodified lines |
| 108 | 112 | /* ecx */ RC_INT | RC_RCX, |
| 109 | 113 | /* edx */ RC_INT | RC_RDX, |
| 110 | 114 | /* xmm0 */ RC_FLOAT | RC_XMM0, |
| 115 | + /* xmm1 */ RC_FLOAT | RC_XMM1, |
| 111 | 116 | /* st0 */ RC_ST0, |
| 112 | 117 | 0, |
| 113 | 118 | 0, |
| @@ -375,7 +380,8 @@ void load(int r, SValue *sv) · 261 unmodified lines |
| 375 | 380 | if ((ft & VT_BTYPE) == VT_FLOAT) { |
| 376 | 381 | b = 0x6e0f66, r = 0; /* movd */ |
| 377 | 382 | } else if ((ft & VT_BTYPE) == VT_DOUBLE) { |
| 378 | | − b = 0x7e0ff3, r = 0; /* movq */ |
| 383 | + b = 0x7e0ff3; /* movq */ |
| 384 | + r -= TREG_XMM0; |
| 379 | 385 | } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
| 380 | 386 | b = 0xdb, r = 5; /* fldt */ |
| 381 | 387 | } else if ((ft & VT_TYPE) == VT_BYTE) { |
| @@ -387,6 +393,9 @@ void load(int r, SValue *sv) · 5 unmodified lines |
| 387 | 393 | } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { |
| 388 | 394 | b = 0xb70f; /* movzwl */ |
| 389 | 395 | } else { |
| 396 | + assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG) |
| 397 | + || ((ft & VT_BTYPE) == VT_PTR) || ((ft & VT_BTYPE) == VT_ENUM) |
| 398 | + || ((ft & VT_BTYPE) == VT_FUNC)); |
| 390 | 399 | ll = is64_type(ft); |
| 391 | 400 | b = 0x8b; |
| 392 | 401 | } |
| @@ -450,18 +459,30 @@ void load(int r, SValue *sv) · 57 unmodified lines |
| 450 | 459 | orex(0,r,0,0); |
| 451 | 460 | oad(0xb8 + REG_VALUE(r), t ^ 1); /* mov $0, r */ |
| 452 | 461 | } else if (v != r) { |
| 453 | | − if (r == TREG_XMM0) { |
| 454 | | − assert(v == TREG_ST0); |
| 455 | | − /* gen_cvt_ftof(VT_DOUBLE); */ |
| 456 | | − o(0xf0245cdd); /* fstpl -0x10(%rsp) */ |
| 457 | | − /* movsd -0x10(%rsp),%xmm0 */ |
| 458 | | − o(0x44100ff2); |
| 459 | | − o(0xf024); |
| 462 | + if ((r == TREG_XMM0) || (r == TREG_XMM1)) { |
| 463 | + if (v == TREG_ST0) { |
| 464 | + /* gen_cvt_ftof(VT_DOUBLE); */ |
| 465 | + o(0xf0245cdd); /* fstpl -0x10(%rsp) */ |
| 466 | + /* movsd -0x10(%rsp),%xmmN */ |
| 467 | + o(0x100ff2); |
| 468 | + o(0x44 + ((r - TREG_XMM0) << 3)); /* %xmmN */ |
| 469 | + o(0xf024); |
| 470 | + } else { |
| 471 | + assert((v == TREG_XMM0) || (v == TREG_XMM1)); |
| 472 | + if ((ft & VT_BTYPE) == VT_FLOAT) { |
| 473 | + o(0x100ff3); |
| 474 | + } else { |
| 475 | + assert((ft & VT_BTYPE) == VT_DOUBLE); |
| 476 | + o(0x100ff2); |
| 477 | + } |
| 478 | + o(0xc0 + (v - TREG_XMM0) + ((r - TREG_XMM0) << 3)); |
| 479 | + } |
| 460 | 480 | } else if (r == TREG_ST0) { |
| 461 | | − assert(v == TREG_XMM0); |
| 481 | + assert((v == TREG_XMM0) || (v == TREG_XMM1)); |
| 462 | 482 | /* gen_cvt_ftof(VT_LDOUBLE); */ |
| 463 | 483 | /* movsd %xmm0,-0x10(%rsp) */ |
| 464 | | − o(0x44110ff2); |
| 484 | + o(0x110ff2); |
| 485 | + o(0x44 + ((r - TREG_XMM0) << 3)); /* %xmmN */ |
| 465 | 486 | o(0xf024); |
| 466 | 487 | o(0xf02444dd); /* fldl -0x10(%rsp) */ |
| 467 | 488 | } else { |
| @@ -510,7 +531,7 @@ void store(int r, SValue *v) · 42 unmodified lines |
| 510 | 531 | o(0x66); |
| 511 | 532 | o(pic); |
| 512 | 533 | o(0xd60f); /* movq */ |
| 513 | | − r = 0; |
| 534 | + r -= TREG_XMM0; |
| 514 | 535 | } else if (bt == VT_LDOUBLE) { |
| 515 | 536 | o(0xc0d9); /* fld %st(0) */ |
| 516 | 537 | o(pic); |
| @@ -679,7 +700,7 @@ void gfunc_call(int nb_args) · 162 unmodified lines |
| 679 | 700 | struct_size += size; |
| 680 | 701 | |
| 681 | 702 | } else if (is_sse_float(vtop->type.t)) { |
| 682 | | − gv(RC_FLOAT); /* only one float register */ |
| 703 | + gv(RC_XMM0); /* only one float register */ |
| 683 | 704 | j = --gen_reg; |
| 684 | 705 | if (j >= REGN) { |
| 685 | 706 | /* movq %xmm0, j*8(%rsp) */ |
| @@ -861,6 +882,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) { · 175 unmodified lines |
| 861 | 882 | case VT_LLONG: |
| 862 | 883 | case VT_BOOL: |
| 863 | 884 | case VT_PTR: |
| 885 | + case VT_FUNC: |
| 864 | 886 | case VT_ENUM: return x86_64_mode_integer; |
| 865 | 887 | |
| 866 | 888 | case VT_FLOAT: |
| @@ -881,6 +903,8 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) { · 14 unmodified lines |
| 881 | 903 | |
| 882 | 904 | return mode; |
| 883 | 905 | } |
| 906 | + |
| 907 | + assert(0); |
| 884 | 908 | } |
| 885 | 909 | |
| 886 | 910 | static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *reg_count) { |
| @@ -963,6 +987,14 @@ static const uint8_t arg_regs[REGN] = { · 76 unmodified lines |
| 963 | 987 | TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 |
| 964 | 988 | }; |
| 965 | 989 | |
| 990 | +static int arg_prepare_reg(int idx) { |
| 991 | + if (idx == 2 || idx == 3) |
| 992 | + /* idx=2: r10, idx=3: r11 */ |
| 993 | + return idx + 8; |
| 994 | + else |
| 995 | + return arg_regs[idx]; |
| 996 | +} |
| 997 | + |
| 966 | 998 | /* Generate function call. The function address is pushed first, then |
| 967 | 999 | all the parameters in call order. This functions pops all the |
| 968 | 1000 | parameters and the function address. */ |
| @@ -1051,7 +1083,7 @@ void gfunc_call(int nb_args) · 82 unmodified lines |
| 1051 | 1083 | |
| 1052 | 1084 | case x86_64_mode_sse: |
| 1053 | 1085 | if (sse_reg > 8) { |
| 1054 | | − gv(RC_FLOAT); |
| 1086 | + gv(RC_XMM0); |
| 1055 | 1087 | o(0x50); /* push $rax */ |
| 1056 | 1088 | /* movq %xmm0, (%rsp) */ |
| 1057 | 1089 | o(0x04d60f66); |
| @@ -1097,15 +1129,18 @@ void gfunc_call(int nb_args) · 39 unmodified lines |
| 1097 | 1129 | break; |
| 1098 | 1130 | |
| 1099 | 1131 | case x86_64_mode_sse: |
| 1100 | | − if (sse_reg > 8) { |
| 1101 | | − sse_reg -= reg_count; |
| 1102 | | − } else { |
| 1103 | | − for (j = 0; j < reg_count; ++j) { |
| 1104 | | − --sse_reg; |
| 1105 | | − gv(RC_FLOAT); /* only one float register */ |
| 1132 | + sse_reg -= reg_count; |
| 1133 | + if (sse_reg + reg_count <= 8) { |
| 1134 | + gv(RC_XMM0); /* only one float register */ |
| 1135 | + if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ |
| 1106 | 1136 | /* movaps %xmm0, %xmmN */ |
| 1107 | 1137 | o(0x280f); |
| 1108 | 1138 | o(0xc0 + (sse_reg << 3)); |
| 1139 | + if (reg_count == 2) { |
| 1140 | + /* movaps %xmm1, %xmmN */ |
| 1141 | + o(0x280f); |
| 1142 | + o(0xc1 + ((sse_reg+1) << 3)); |
| 1143 | + } |
| 1109 | 1144 | } |
| 1110 | 1145 | } |
| 1111 | 1146 | break; |
| @@ -1113,16 +1148,17 @@ void gfunc_call(int nb_args) · 1 unmodified line |
| 1113 | 1148 | case x86_64_mode_integer: |
| 1114 | 1149 | /* simple type */ |
| 1115 | 1150 | /* XXX: implicit cast ? */ |
| 1116 | | − if (gen_reg > 8) { |
| 1117 | | − gen_reg -= reg_count; |
| 1118 | | − } else { |
| 1119 | | − for (j = 0; j < reg_count; ++j) { |
| 1120 | | − --gen_reg; |
| 1121 | | − int d = arg_regs[gen_reg]; |
| 1122 | | − r = gv(RC_INT); |
| 1123 | | − if (gen_reg == 2 || gen_reg == 3) |
| 1124 | | − /* gen_reg=2: r10, gen_reg=3: r11 */ |
| 1125 | | − d = gen_reg + 8; |
| 1151 | + gen_reg -= reg_count; |
| 1152 | + if (gen_reg + reg_count <= REGN) { |
| 1153 | + r = gv((reg_count == 1) ? RC_INT : RC_IRET); |
| 1154 | + int d = arg_prepare_reg(gen_reg); |
| 1155 | + orex(1,d,r,0x89); /* mov */ |
| 1156 | + o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); |
| 1157 | + if (reg_count == 2) { |
| 1158 | + /* Second word of two-word value should always be in rdx |
| 1159 | + this case is handled via RC_IRET */ |
| 1160 | + r = TREG_RDX; |
| 1161 | + d = arg_prepare_reg(gen_reg+1); |
| 1126 | 1162 | orex(1,d,r,0x89); /* mov */ |
| 1127 | 1163 | o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); |
| 1128 | 1164 | } |
| @@ -1263,13 +1299,13 @@ void gfunc_prolog(CType *func_type) · 134 unmodified lines |
| 1263 | 1299 | case x86_64_mode_sse: |
| 1264 | 1300 | if (sse_param_index + reg_count <= 8) { |
| 1265 | 1301 | /* save arguments passed by register */ |
| 1302 | + loc -= reg_count * 8; |
| 1303 | + param_addr = loc; |
| 1266 | 1304 | for (i = 0; i < reg_count; ++i) { |
| 1267 | | − loc -= 8; |
| 1268 | 1305 | o(0xd60f66); /* movq */ |
| 1269 | | − gen_modrm(sse_param_index, VT_LOCAL, NULL, loc); |
| 1306 | + gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + i*8); |
| 1270 | 1307 | ++sse_param_index; |
| 1271 | 1308 | } |
| 1272 | | − param_addr = loc; |
| 1273 | 1309 | } else { |
| 1274 | 1310 | param_addr = addr; |
| 1275 | 1311 | addr += size; |
| @@ -1286,11 +1322,12 @@ void gfunc_prolog(CType *func_type) · 10 unmodified lines |
| 1286 | 1322 | case x86_64_mode_integer: { |
| 1287 | 1323 | if (reg_param_index + reg_count <= REGN) { |
| 1288 | 1324 | /* save arguments passed by register */ |
| 1325 | + loc -= reg_count * 8; |
| 1326 | + param_addr = loc; |
| 1289 | 1327 | for (i = 0; i < reg_count; ++i) { |
| 1290 | | − push_arg_reg(reg_param_index); |
| 1328 | + gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + i*8); |
| 1291 | 1329 | ++reg_param_index; |
| 1292 | 1330 | } |
| 1293 | | − param_addr = loc; |
| 1294 | 1331 | } else { |
| 1295 | 1332 | param_addr = addr; |
| 1296 | 1333 | addr += size; |
| @@ -1547,12 +1584,12 @@ void gen_opl(int op) · 250 unmodified lines |
| 1547 | 1584 | |
| 1548 | 1585 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
| 1549 | 1586 | two operands are guaranted to have the same floating point type */ |
| 1550 | | −/* XXX: need to use ST1 too */ |
| 1587 | +/* XXX: need to use ST1 and XMM1 too */ |
| 1551 | 1588 | void gen_opf(int op) |
| 1552 | 1589 | { |
| 1553 | 1590 | int a, ft, fc, swapped, r; |
| 1554 | 1591 | int float_type = |
| 1555 | | − (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT; |
| 1592 | + (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_XMM0; /* to avoid xmm1 handling for now */ |
| 1556 | 1593 | |
| 1557 | 1594 | /* convert constants to memory references */ |
| 1558 | 1595 | if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
| @@ -1803,9 +1840,9 @@ void gen_cvt_ftof(int t) · 244 unmodified lines |
| 1803 | 1840 | ft = vtop->type.t; |
| 1804 | 1841 | bt = ft & VT_BTYPE; |
| 1805 | 1842 | tbt = t & VT_BTYPE; |
| 1806 | | − |
| 1843 | + |
| 1807 | 1844 | if (bt == VT_FLOAT) { |
| 1808 | | − gv(RC_FLOAT); |
| 1845 | + gv(RC_XMM0); /* to avoid rewriting to handle xmm1 for now */ |
| 1809 | 1846 | if (tbt == VT_DOUBLE) { |
| 1810 | 1847 | o(0xc0140f); /* unpcklps */ |
| 1811 | 1848 | o(0xc05a0f); /* cvtps2pd */ |
| @@ -1817,7 +1854,7 @@ void gen_cvt_ftof(int t) · 5 unmodified lines |
| 1817 | 1854 | vtop->r = TREG_ST0; |
| 1818 | 1855 | } |
| 1819 | 1856 | } else if (bt == VT_DOUBLE) { |
| 1820 | | − gv(RC_FLOAT); |
| 1857 | + gv(RC_XMM0); /* to avoid rewriting to handle xmm1 for now */ |
| 1821 | 1858 | if (tbt == VT_FLOAT) { |
| 1822 | 1859 | o(0xc0140f66); /* unpcklpd */ |
| 1823 | 1860 | o(0xc05a0f66); /* cvtpd2ps */ |
| @@ -1857,7 +1894,7 @@ void gen_cvt_ftoi(int t) · 33 unmodified lines |
| 1857 | 1894 | bt = VT_DOUBLE; |
| 1858 | 1895 | } |
| 1859 | 1896 | |
| 1860 | | − gv(RC_FLOAT); |
| 1897 | + gv(RC_XMM0); |
| 1861 | 1898 | if (t != VT_INT) |
| 1862 | 1899 | size = 8; |
| 1863 | 1900 | else |