| @@ -592,6 +592,31 @@ static void gcall_or_jmp(int is_jmp) · 591 unmodified lines |
| 592 | } | 592 | } |
| 593 | } | 593 | } |
| 594 | | 594 | |
| | 595 | void struct_copy(SValue *d, SValue *s, SValue *c) |
| | 596 | { |
| | 597 | if(!c->c.i) |
| | 598 | return; |
| | 599 | save_reg(TREG_RCX); |
| | 600 | load(TREG_RCX, c); |
| | 601 | load(TREG_RDI, d); |
| | 602 | load(TREG_RSI, s); |
| | 603 | o(0xa4f3);// rep movsb |
| | 604 | } |
| | 605 | |
| | 606 | void gen_putz(SValue *d, int size) |
| | 607 | { |
| | 608 | if(!size) |
| | 609 | return; |
| | 610 | save_reg(TREG_RAX); |
| | 611 | o(0xb0); |
| | 612 | g(0x00); |
| | 613 | save_reg(TREG_RCX); |
| | 614 | o(0xb8 + REG_VALUE(TREG_RCX)); /* mov $xx, r */ |
| | 615 | gen_le32(size); |
| | 616 | load(TREG_RDI, d); |
| | 617 | o(0xaaf3);//rep stos |
| | 618 | } |
| | 619 | |
| 595 | #ifdef TCC_TARGET_PE | 620 | #ifdef TCC_TARGET_PE |
| 596 | | 621 | |
| 597 | #define REGN 4 | 622 | #define REGN 4 |
| @@ -1060,14 +1085,6 @@ static const uint8_t arg_regs[REGN] = { · 462 unmodified lines |
| 1060 | TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 | 1085 | TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 |
| 1061 | }; | 1086 | }; |
| 1062 | | 1087 | |
| 1063 | static int arg_prepare_reg(int idx) { | | |
| 1064 | if (idx == 2 || idx == 3) | | |
| 1065 | /* idx=2: r10, idx=3: r11 */ | | |
| 1066 | return idx + 8; | | |
| 1067 | else | | |
| 1068 | return arg_regs[idx]; | | |
| 1069 | } | | |
| 1070 | | | |
| 1071 | /* Generate function call. The function address is pushed first, then | 1088 | /* Generate function call. The function address is pushed first, then |
| 1072 | all the parameters in call order. This functions pops all the | 1089 | all the parameters in call order. This functions pops all the |
| 1073 | parameters and the function address. */ | 1090 | parameters and the function address. */ |
| @@ -1080,6 +1097,9 @@ void gfunc_call(int nb_args) · 6 unmodified lines |
| 1080 | int nb_sse_args = 0; | 1097 | int nb_sse_args = 0; |
| 1081 | int sse_reg, gen_reg; | 1098 | int sse_reg, gen_reg; |
| 1082 | | 1099 | |
| | 1100 | /* fetch cpu flag before the following sub will change the value */ |
| | 1101 | if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP) |
| | 1102 | gv(RC_INT); |
| 1083 | /* calculate the number of integer/float register arguments */ | 1103 | /* calculate the number of integer/float register arguments */ |
| 1084 | for(i = 0; i < nb_args; i++) { | 1104 | for(i = 0; i < nb_args; i++) { |
| 1085 | mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); | 1105 | mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, ®_count); |
| @@ -1276,7 +1296,7 @@ void gfunc_call(int nb_args) · 190 unmodified lines |
| 1276 | } | 1296 | } |
| 1277 | | 1297 | |
| 1278 | /* XXX This should be superfluous. */ | 1298 | /* XXX This should be superfluous. */ |
| 1279 | save_regs(0); /* save used temporary registers */ | 1299 | // save_regs(0); /* save used temporary registers */ |
| 1280 | | 1300 | |
| 1281 | /* then, we prepare register passing arguments. | 1301 | /* then, we prepare register passing arguments. |
| 1282 | Note that we cannot set RDX and RCX in this loop because gv() | 1302 | Note that we cannot set RDX and RCX in this loop because gv() |
| @@ -1289,36 +1309,34 @@ void gfunc_call(int nb_args) · 6 unmodified lines |
| 1289 | /* Alter stack entry type so that gv() knows how to treat it */ | 1309 | /* Alter stack entry type so that gv() knows how to treat it */ |
| 1290 | vtop->type = type; | 1310 | vtop->type = type; |
| 1291 | if (mode == x86_64_mode_sse) { | 1311 | if (mode == x86_64_mode_sse) { |
| 1292 | if (reg_count == 2) { | 1312 | sse_reg -= reg_count; |
| 1293 | sse_reg -= 2; | 1313 | if (sse_reg + reg_count <= 8) { |
| 1294 | gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */ | 1314 | if (reg_count == 2) { |
| 1295 | if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */ | 1315 | ex_rc = RC_XMM0 << (sse_reg + 1); |
| 1296 | /* movaps %xmm0, %xmmN */ | 1316 | gv(RC_XMM0 << sse_reg); |
| 1297 | o(0x280f); | 1317 | }else{ |
| 1298 | o(0xc0 + (sse_reg << 3)); | 1318 | assert(reg_count == 1); |
| 1299 | /* movaps %xmm1, %xmmN */ | 1319 | /* Load directly to register */ |
| 1300 | o(0x280f); | 1320 | gv(RC_XMM0 << sse_reg); |
| 1301 | o(0xc1 + ((sse_reg+1) << 3)); | 1321 | } |
| 1302 | } | 1322 | } |
| 1303 | } else { | | |
| 1304 | assert(reg_count == 1); | | |
| 1305 | --sse_reg; | | |
| 1306 | /* Load directly to register */ | | |
| 1307 | gv(RC_XMM0 << sse_reg); | | |
| 1308 | } | | |
| 1309 | } else if (mode == x86_64_mode_integer) { | 1323 | } else if (mode == x86_64_mode_integer) { |
| 1310 | /* simple type */ | 1324 | /* simple type */ |
| 1311 | /* XXX: implicit cast ? */ | 1325 | /* XXX: implicit cast ? */ |
| | 1326 | int d; |
| 1312 | gen_reg -= reg_count; | 1327 | gen_reg -= reg_count; |
| 1313 | r = gv(RC_INT); | 1328 | if (gen_reg + reg_count <= REGN) { |
| 1314 | int d = arg_prepare_reg(gen_reg); | 1329 | if (reg_count == 2) { |
| 1315 | orex(1,d,r,0x89); /* mov */ | 1330 | d = arg_regs[gen_reg+1]; |
| 1316 | o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); | 1331 | ex_rc = reg_classes[d] & ~RC_MASK; |
| 1317 | if (reg_count == 2) { | 1332 | d = arg_regs[gen_reg]; |
| 1318 | d = arg_prepare_reg(gen_reg+1); | 1333 | gv(reg_classes[d] & ~RC_MASK); |
| 1319 | orex(1,d,vtop->r2,0x89); /* mov */ | 1334 | }else{ |
| 1320 | o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); | 1335 | assert(reg_count == 1); |
| 1321 | } | 1336 | d = arg_regs[gen_reg]; |
| | 1337 | gv(reg_classes[d] & ~RC_MASK); |
| | 1338 | } |
| | 1339 | } |
| 1322 | } | 1340 | } |
| 1323 | vtop--; | 1341 | vtop--; |
| 1324 | } | 1342 | } |
| @@ -1330,15 +1348,6 @@ void gfunc_call(int nb_args) · 5 unmodified lines |
| 1330 | (or edx/ecx) currently, which the below writes would clobber. | 1348 | (or edx/ecx) currently, which the below writes would clobber. |
| 1331 | So evict all remaining operands here. */ | 1349 | So evict all remaining operands here. */ |
| 1332 | save_regs(0); | 1350 | save_regs(0); |
| 1333 | | | |
| 1334 | /* Copy R10 and R11 into RDX and RCX, respectively */ | | |
| 1335 | if (nb_reg_args > 2) { | | |
| 1336 | o(0xd2894c); /* mov %r10, %rdx */ | | |
| 1337 | if (nb_reg_args > 3) { | | |
| 1338 | o(0xd9894c); /* mov %r11, %rcx */ | | |
| 1339 | } | | |
| 1340 | } | | |
| 1341 | | | |
| 1342 | oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ | 1351 | oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ |
| 1343 | gcall_or_jmp(0); | 1352 | gcall_or_jmp(0); |
| 1344 | if (args_size) | 1353 | if (args_size) |