This unifies VT_CMP with VT_JMP(i) by using mostly VT_CMP with both a positive and a negative jump target list. Such we can delay putting the non-inverted or inverted jump until we can see which one is nore suitable (in most cases). example: if (a && b || c && d) e = 0; before this patch: a: 8b 45 fc mov 0xfffffffc(%ebp),%eax d: 83 f8 00 cmp $0x0,%eax 10: 0f 84 11 00 00 00 je 27 <main+0x27> 16: 8b 45 f8 mov 0xfffffff8(%ebp),%eax 19: 83 f8 00 cmp $0x0,%eax 1c: 0f 84 05 00 00 00 je 27 <main+0x27> 22: e9 22 00 00 00 jmp 49 <main+0x49> 27: 8b 45 f4 mov 0xfffffff4(%ebp),%eax 2a: 83 f8 00 cmp $0x0,%eax 2d: 0f 84 11 00 00 00 je 44 <main+0x44> 33: 8b 45 f0 mov 0xfffffff0(%ebp),%eax 36: 83 f8 00 cmp $0x0,%eax 39: 0f 84 05 00 00 00 je 44 <main+0x44> 3f: e9 05 00 00 00 jmp 49 <main+0x49> 44: e9 08 00 00 00 jmp 51 <main+0x51> 49: b8 00 00 00 00 mov $0x0,%eax 4e: 89 45 ec mov %eax,0xffffffec(%ebp) 51: ... with this patch: a: 8b 45 fc mov 0xfffffffc(%ebp),%eax d: 83 f8 00 cmp $0x0,%eax 10: 0f 84 0c 00 00 00 je 22 <main+0x22> 16: 8b 45 f8 mov 0xfffffff8(%ebp),%eax 19: 83 f8 00 cmp $0x0,%eax 1c: 0f 85 18 00 00 00 jne 3a <main+0x3a> 22: 8b 45 f4 mov 0xfffffff4(%ebp),%eax 25: 83 f8 00 cmp $0x0,%eax 28: 0f 84 14 00 00 00 je 42 <main+0x42> 2e: 8b 45 f0 mov 0xfffffff0(%ebp),%eax 31: 83 f8 00 cmp $0x0,%eax 34: 0f 84 08 00 00 00 je 42 <main+0x42> 3a: b8 00 00 00 00 mov $0x0,%eax 3f: 89 45 ec mov %eax,0xffffffec(%ebp) 42: ...
Unified · Split
| @@ -125,7 +125,7 @@ DEF-i386-win32 = -DTCC_TARGET_PE -DTCC_TARGET_I386 · 124 unmodified lines | ||
| 125 | 125 | DEF-x86_64-win32= -DTCC_TARGET_PE -DTCC_TARGET_X86_64 |
| 126 | 126 | DEF-x86_64-osx = -DTCC_TARGET_MACHO -DTCC_TARGET_X86_64 |
| 127 | 127 | DEF-arm-wince = -DTCC_TARGET_PE -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DTCC_ARM_HARDFLOAT |
| 128 | −DEF-arm64 = -DTCC_TARGET_ARM64 | |
| 128 | +DEF-arm64 = -DTCC_TARGET_ARM64 -Wno-format | |
| 129 | 129 | DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs |
| 130 | 130 | DEF-arm-fpa = -DTCC_TARGET_ARM |
| 131 | 131 | DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12 |
| @@ -1419,7 +1419,7 @@ ST_FUNC void gen_fill_nops(int bytes) · 1418 unmodified lines | ||
| 1419 | 1419 | } |
| 1420 | 1420 | |
| 1421 | 1421 | /* generate a jump to a label */ |
| 1422 | −int gjmp(int t) | |
| 1422 | +ST_FUNC int gjmp(int t) | |
| 1423 | 1423 | { |
| 1424 | 1424 | int r; |
| 1425 | 1425 | if (nocode_wanted) |
| @@ -1430,51 +1430,37 @@ int gjmp(int t) · 4 unmodified lines | ||
| 1430 | 1430 | } |
| 1431 | 1431 | |
| 1432 | 1432 | /* generate a jump to a fixed address */ |
| 1433 | −void gjmp_addr(int a) | |
| 1433 | +ST_FUNC void gjmp_addr(int a) | |
| 1434 | 1434 | { |
| 1435 | 1435 | gjmp(a); |
| 1436 | 1436 | } |
| 1437 | 1437 | |
| 1438 | −/* generate a test. set 'inv' to invert test. Stack entry is popped */ | |
| 1439 | −int gtst(int inv, int t) | |
| 1438 | +ST_FUNC int gjmp_cond(int op, int t) | |
| 1440 | 1439 | { |
| 1441 | − int v, r; | |
| 1442 | − uint32_t op; | |
| 1443 | − | |
| 1444 | − v = vtop->r & VT_VALMASK; | |
| 1440 | + int r; | |
| 1441 | + if (nocode_wanted) | |
| 1442 | + return t; | |
| 1445 | 1443 | r=ind; |
| 1444 | + op=mapcc(op); | |
| 1445 | + op|=encbranch(r,t,1); | |
| 1446 | + o(op); | |
| 1447 | + return r; | |
| 1448 | +} | |
| 1446 | 1449 | |
| 1447 | − if (nocode_wanted) { | |
| 1448 | − ; | |
| 1449 | − } else if (v == VT_CMP) { | |
| 1450 | − op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); | |
| 1451 | − op|=encbranch(r,t,1); | |
| 1452 | − o(op); | |
| 1453 | − t=r; | |
| 1454 | − } else if (v == VT_JMP || v == VT_JMPI) { | |
| 1455 | − if ((v & 1) == inv) { | |
| 1456 | − if(!vtop->c.i) | |
| 1457 | − vtop->c.i=t; | |
| 1458 | − else { | |
| 1459 | − uint32_t *x; | |
| 1460 | − int p,lp; | |
| 1461 | − if(t) { | |
| 1462 | − p = vtop->c.i; | |
| 1463 | − do { | |
| 1464 | − p = decbranch(lp=p); | |
| 1465 | − } while(p); | |
| 1466 | − x = (uint32_t *)(cur_text_section->data + lp); | |
| 1467 | − *x &= 0xff000000; | |
| 1468 | − *x |= encbranch(lp,t,1); | |
| 1469 | − } | |
| 1470 | − t = vtop->c.i; | |
| 1471 | − } | |
| 1472 | − } else { | |
| 1473 | − t = gjmp(t); | |
| 1474 | − gsym(vtop->c.i); | |
| 1475 | − } | |
| 1450 | +ST_FUNC int gjmp_append(int n, int t) | |
| 1451 | +{ | |
| 1452 | + uint32_t *x; | |
| 1453 | + int p,lp; | |
| 1454 | + if(n) { | |
| 1455 | + p = n; | |
| 1456 | + do { | |
| 1457 | + p = decbranch(lp=p); | |
| 1458 | + } while(p); | |
| 1459 | + x = (uint32_t *)(cur_text_section->data + lp); | |
| 1460 | + *x &= 0xff000000; | |
| 1461 | + *x |= encbranch(lp,t,1); | |
| 1462 | + t = n; | |
| 1476 | 1463 | } |
| 1477 | − vtop--; | |
| 1478 | 1464 | return t; |
| 1479 | 1465 | } |
| 1480 | 1466 | |
| @@ -1611,10 +1597,8 @@ void gen_opi(int op) · 130 unmodified lines | ||
| 1611 | 1597 | o(opc|(r<<12)|fr); |
| 1612 | 1598 | done: |
| 1613 | 1599 | vtop--; |
| 1614 | − if (op >= TOK_ULT && op <= TOK_GT) { | |
| 1615 | − vtop->r = VT_CMP; | |
| 1616 | − vtop->c.i = op; | |
| 1617 | − } | |
| 1600 | + if (op >= TOK_ULT && op <= TOK_GT) | |
| 1601 | + vset_VT_CMP(op); | |
| 1618 | 1602 | break; |
| 1619 | 1603 | case 2: |
| 1620 | 1604 | opc=0xE1A00000|(opc<<5); |
| @@ -1730,9 +1714,7 @@ void gen_opf(int op) · 109 unmodified lines | ||
| 1730 | 1714 | case TOK_UGE: op=TOK_GE; break; |
| 1731 | 1715 | case TOK_UGT: op=TOK_GT; break; |
| 1732 | 1716 | } |
| 1733 | − | |
| 1734 | − vtop->r = VT_CMP; | |
| 1735 | − vtop->c.i = op; | |
| 1717 | + vset_VT_CMP(op); | |
| 1736 | 1718 | return; |
| 1737 | 1719 | } |
| 1738 | 1720 | r=gv(RC_FLOAT); |
| @@ -1934,8 +1916,9 @@ void gen_opf(int op) · 195 unmodified lines | ||
| 1934 | 1916 | } else { |
| 1935 | 1917 | r2=fpr(gv(RC_FLOAT)); |
| 1936 | 1918 | } |
| 1937 | − vtop[-1].r = VT_CMP; | |
| 1938 | − vtop[-1].c.i = op; | |
| 1919 | + --vtop; | |
| 1920 | + vset_VT_CMP(op); | |
| 1921 | + ++vtop; | |
| 1939 | 1922 | } else { |
| 1940 | 1923 | tcc_error("unknown fp op %x!",op); |
| 1941 | 1924 | return; |
| @@ -91,6 +91,9 @@ static uint32_t fltr(int r) · 90 unmodified lines | ||
| 91 | 91 | return r - TREG_F(0); |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | +#define dprintf(x) ((void)(tcc_state->verbose == 2 && printf x)) | |
| 95 | +//#define dprintf(x) | |
| 96 | + | |
| 94 | 97 | // Add an instruction to text section: |
| 95 | 98 | ST_FUNC void o(unsigned int c) |
| 96 | 99 | { |
| @@ -100,6 +103,7 @@ ST_FUNC void o(unsigned int c) · 3 unmodified lines | ||
| 100 | 103 | if (ind1 > cur_text_section->data_allocated) |
| 101 | 104 | section_realloc(cur_text_section, ind1); |
| 102 | 105 | write32le(cur_text_section->data + ind, c); |
| 106 | + dprintf(("o %04x : %08x\n", ind, c)); //gr | |
| 103 | 107 | ind = ind1; |
| 104 | 108 | } |
| 105 | 109 | |
| @@ -232,6 +236,7 @@ ST_FUNC void gsym_addr(int t_, int a_) · 126 unmodified lines | ||
| 232 | 236 | tcc_error("branch out of range"); |
| 233 | 237 | write32le(ptr, (a - t == 4 ? 0xd503201f : // nop |
| 234 | 238 | 0x14000000 | ((a - t) >> 2 & 0x3ffffff))); // b |
| 239 | + dprintf((". gsym TARG=%04x ADDR=%04x\n", t, a)); //gr | |
| 235 | 240 | t = next; |
| 236 | 241 | } |
| 237 | 242 | } |
| @@ -440,6 +445,8 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend) · 202 unmodified lines | ||
| 440 | 445 | } |
| 441 | 446 | } |
| 442 | 447 | |
| 448 | +static void arm64_load_cmp(int r, SValue *sv); | |
| 449 | + | |
| 443 | 450 | ST_FUNC void load(int r, SValue *sv) |
| 444 | 451 | { |
| 445 | 452 | int svtt = sv->type.t; |
| @@ -531,6 +538,11 @@ ST_FUNC void load(int r, SValue *sv) · 85 unmodified lines | ||
| 531 | 538 | return; |
| 532 | 539 | } |
| 533 | 540 | |
| 541 | + if (svr == VT_CMP) { | |
| 542 | + arm64_load_cmp(r, sv); | |
| 543 | + return; | |
| 544 | + } | |
| 545 | + | |
| 534 | 546 | printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul); |
| 535 | 547 | assert(0); |
| 536 | 548 | } |
| @@ -1284,6 +1296,7 @@ ST_FUNC void gen_fill_nops(int bytes) · 747 unmodified lines | ||
| 1284 | 1296 | ST_FUNC int gjmp(int t) |
| 1285 | 1297 | { |
| 1286 | 1298 | int r = ind; |
| 1299 | + dprintf((". gjmp T=%04x\n", t)); //gr | |
| 1287 | 1300 | if (nocode_wanted) |
| 1288 | 1301 | return t; |
| 1289 | 1302 | o(t); |
| @@ -1295,11 +1308,57 @@ ST_FUNC void gjmp_addr(int a) · 5 unmodified lines | ||
| 1295 | 1308 | { |
| 1296 | 1309 | assert(a - ind + 0x8000000 < 0x10000000); |
| 1297 | 1310 | o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff)); |
| 1311 | + dprintf((". gjmp_addr T=%04x\n", a)); //gr | |
| 1298 | 1312 | } |
| 1299 | 1313 | |
| 1300 | −ST_FUNC int gtst(int inv, int t) | |
| 1314 | +ST_FUNC int gjmp_append(int n, int t) | |
| 1315 | +{ | |
| 1316 | + void *p; | |
| 1317 | + /* insert vtop->c jump list in t */ | |
| 1318 | + if (n) { | |
| 1319 | + uint32_t n1 = n, n2; | |
| 1320 | + while ((n2 = read32le(p = cur_text_section->data + n1))) | |
| 1321 | + n1 = n2; | |
| 1322 | + write32le(p, t); | |
| 1323 | + t = n; | |
| 1324 | + } | |
| 1325 | + return t; | |
| 1326 | +} | |
| 1327 | + | |
| 1328 | +void arm64_vset_VT_CMP(int op) | |
| 1329 | +{ | |
| 1330 | + if (op >= TOK_ULT && op <= TOK_GT) { | |
| 1331 | + vtop->cmp_r = vtop->r; | |
| 1332 | + vset_VT_CMP(0x80); | |
| 1333 | + dprintf((". set VT_CMP OP(%s) R=%x\n", get_tok_str(op, 0), vtop->cmp_r)); | |
| 1334 | + } | |
| 1335 | +} | |
| 1336 | + | |
| 1337 | +static void arm64_gen_opil(int op, uint32_t l); | |
| 1338 | + | |
| 1339 | +static void arm64_load_cmp(int r, SValue *sv) | |
| 1340 | +{ | |
| 1341 | + sv->r = sv->cmp_r; | |
| 1342 | + dprintf((". load VT_CMP OP(%x), R=%x/%x\n", (int)sv->c.i, sv->r, r)); | |
| 1343 | + if (sv->c.i & 1) { | |
| 1344 | + vpushi(1); | |
| 1345 | + arm64_gen_opil('^', 0); | |
| 1346 | + } | |
| 1347 | + if (r != sv->r) { | |
| 1348 | + load(r, sv); | |
| 1349 | + sv->r = r; | |
| 1350 | + } | |
| 1351 | + dprintf((". load VT_CMP done\n")); //gr | |
| 1352 | +} | |
| 1353 | + | |
| 1354 | +ST_FUNC int gjmp_cond(int op, int t) | |
| 1301 | 1355 | { |
| 1302 | 1356 | int bt = vtop->type.t & VT_BTYPE; |
| 1357 | + | |
| 1358 | + int inv = op & 1; | |
| 1359 | + vtop->r = vtop->cmp_r; | |
| 1360 | + dprintf((". gjmp_cond OP(%x) R=%x T=%04x\n", op, vtop->r, t)); //gr | |
| 1361 | + | |
| 1303 | 1362 | if (bt == VT_LDOUBLE) { |
| 1304 | 1363 | uint32_t a, b, f = fltr(gv(RC_FLOAT)); |
| 1305 | 1364 | a = get_reg(RC_INT); |
| @@ -1324,7 +1383,6 @@ ST_FUNC int gtst(int inv, int t) · 18 unmodified lines | ||
| 1324 | 1383 | uint32_t a = intr(gv(RC_INT)); |
| 1325 | 1384 | o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8 |
| 1326 | 1385 | } |
| 1327 | − --vtop; | |
| 1328 | 1386 | return gjmp(t); |
| 1329 | 1387 | } |
| 1330 | 1388 | |
| @@ -1553,11 +1611,13 @@ static void arm64_gen_opil(int op, uint32_t l) · 222 unmodified lines | ||
| 1553 | 1611 | ST_FUNC void gen_opi(int op) |
| 1554 | 1612 | { |
| 1555 | 1613 | arm64_gen_opil(op, 0); |
| 1614 | + arm64_vset_VT_CMP(op); | |
| 1556 | 1615 | } |
| 1557 | 1616 | |
| 1558 | 1617 | ST_FUNC void gen_opl(int op) |
| 1559 | 1618 | { |
| 1560 | 1619 | arm64_gen_opil(op, 1); |
| 1620 | + arm64_vset_VT_CMP(op); | |
| 1561 | 1621 | } |
| 1562 | 1622 | |
| 1563 | 1623 | ST_FUNC void gen_opf(int op) |
| @@ -1657,6 +1717,7 @@ ST_FUNC void gen_opf(int op) · 93 unmodified lines | ||
| 1657 | 1717 | default: |
| 1658 | 1718 | assert(0); |
| 1659 | 1719 | } |
| 1720 | + arm64_vset_VT_CMP(op); | |
| 1660 | 1721 | } |
| 1661 | 1722 | |
| 1662 | 1723 | // Generate sign extension from 32 to 64 bits: |
| @@ -2072,15 +2072,13 @@ void gjmp_addr(int a) · 2071 unmodified lines | ||
| 2072 | 2072 | } |
| 2073 | 2073 | |
| 2074 | 2074 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
| 2075 | −int gtst(int inv, int t) | |
| 2075 | +ST_FUNC int gjmp_cond(int op, int t) | |
| 2076 | 2076 | { |
| 2077 | − int ind1, n; | |
| 2078 | − int v, *p; | |
| 2077 | + int ind1; | |
| 2078 | + int inv = op & 1; | |
| 2079 | + if (nocode_wanted) | |
| 2080 | + return t; | |
| 2079 | 2081 | |
| 2080 | − v = vtop->r & VT_VALMASK; | |
| 2081 | − if (nocode_wanted) { | |
| 2082 | − ; | |
| 2083 | − } else if (v == VT_CMP) { | |
| 2084 | 2082 | /* fast case : can jump directly since flags are set */ |
| 2085 | 2083 | // C67 uses B2 sort of as flags register |
| 2086 | 2084 | ind1 = ind; |
| @@ -2098,16 +2096,18 @@ int gtst(int inv, int t) · 11 unmodified lines | ||
| 2098 | 2096 | C67_NOP(5); |
| 2099 | 2097 | t = ind1; //return where we need to patch |
| 2100 | 2098 | |
| 2101 | − } else if (v == VT_JMP || v == VT_JMPI) { | |
| 2102 | − /* && or || optimization */ | |
| 2103 | − if ((v & 1) == inv) { | |
| 2099 | + return t; | |
| 2100 | +} | |
| 2101 | + | |
| 2102 | +ST_FUNC int gjmp_append(int n0, int t) | |
| 2103 | +{ | |
| 2104 | + if (n0) { | |
| 2105 | + int n = n0, *p; | |
| 2104 | 2106 | /* insert vtop->c jump list in t */ |
| 2105 | 2107 | |
| 2106 | 2108 | // I guess the idea is to traverse to the |
| 2107 | 2109 | // null at the end of the list and store t |
| 2108 | 2110 | // there |
| 2109 | − | |
| 2110 | − n = vtop->c.i; | |
| 2111 | 2111 | while (n != 0) { |
| 2112 | 2112 | p = (int *) (cur_text_section->data + n); |
| 2113 | 2113 | |
| @@ -2117,14 +2117,8 @@ int gtst(int inv, int t) · 3 unmodified lines | ||
| 2117 | 2117 | } |
| 2118 | 2118 | *p |= (t & 0xffff) << 7; |
| 2119 | 2119 | *(p + 1) |= ((t >> 16) & 0xffff) << 7; |
| 2120 | − t = vtop->c.i; | |
| 2121 | − | |
| 2122 | − } else { | |
| 2123 | − t = gjmp(t); | |
| 2124 | − gsym(vtop->c.i); | |
| 2125 | − } | |
| 2120 | + t = n0; | |
| 2126 | 2121 | } |
| 2127 | − vtop--; | |
| 2128 | 2122 | return t; |
| 2129 | 2123 | } |
| 2130 | 2124 | |
| @@ -2200,10 +2194,8 @@ void gen_opi(int op) · 69 unmodified lines | ||
| 2200 | 2194 | ALWAYS_ASSERT(FALSE); |
| 2201 | 2195 | |
| 2202 | 2196 | vtop--; |
| 2203 | − if (op >= TOK_ULT && op <= TOK_GT) { | |
| 2204 | − vtop->r = VT_CMP; | |
| 2205 | − vtop->c.i = op; | |
| 2206 | − } | |
| 2197 | + if (op >= TOK_ULT && op <= TOK_GT) | |
| 2198 | + vset_VT_CMP(0x80); | |
| 2207 | 2199 | break; |
| 2208 | 2200 | case '-': |
| 2209 | 2201 | case TOK_SUBC1: /* sub with carry generation */ |
| @@ -2359,7 +2351,7 @@ void gen_opf(int op) · 149 unmodified lines | ||
| 2359 | 2351 | } else { |
| 2360 | 2352 | ALWAYS_ASSERT(FALSE); |
| 2361 | 2353 | } |
| 2362 | − vtop->r = VT_CMP; // tell TCC that result is in "flags" actually B2 | |
| 2354 | + vset_VT_CMP(0x80); | |
| 2363 | 2355 | } else { |
| 2364 | 2356 | if (op == '+') { |
| 2365 | 2357 | if ((ft & VT_BTYPE) == VT_DOUBLE) { |
| @@ -261,10 +261,10 @@ ST_FUNC void load(int r, SValue *sv) · 260 unmodified lines | ||
| 261 | 261 | o(0xe8 + r); /* mov %ebp, r */ |
| 262 | 262 | } |
| 263 | 263 | } else if (v == VT_CMP) { |
| 264 | − oad(0xb8 + r, 0); /* mov $0, r */ | |
| 265 | 264 | o(0x0f); /* setxx %br */ |
| 266 | 265 | o(fc); |
| 267 | 266 | o(0xc0 + r); |
| 267 | + o(0xc0b60f + r * 0x90000); /* movzbl %al, %eax */ | |
| 268 | 268 | } else if (v == VT_JMP || v == VT_JMPI) { |
| 269 | 269 | t = v & 1; |
| 270 | 270 | oad(0xb8 + r, t); /* mov $1, r */ |
| @@ -692,63 +692,39 @@ ST_FUNC void gjmp_addr(int a) · 421 unmodified lines | ||
| 692 | 692 | } |
| 693 | 693 | } |
| 694 | 694 | |
| 695 | −ST_FUNC void gtst_addr(int inv, int a) | |
| 695 | +#if 0 | |
| 696 | +/* generate a jump to a fixed address */ | |
| 697 | +ST_FUNC void gjmp_cond_addr(int a, int op) | |
| 696 | 698 | { |
| 697 | − int v = vtop->r & VT_VALMASK; | |
| 698 | − if (v == VT_CMP) { | |
| 699 | − inv ^= (vtop--)->c.i; | |
| 700 | − a -= ind + 2; | |
| 701 | − if (a == (char)a) { | |
| 702 | − g(inv - 32); | |
| 703 | − g(a); | |
| 704 | − } else { | |
| 705 | − g(0x0f); | |
| 706 | − oad(inv - 16, a - 4); | |
| 707 | − } | |
| 708 | − } else if ((v & ~1) == VT_JMP) { | |
| 709 | − if ((v & 1) != inv) { | |
| 710 | − gjmp_addr(a); | |
| 711 | − gsym(vtop->c.i); | |
| 712 | − } else { | |
| 713 | − gsym(vtop->c.i); | |
| 714 | − o(0x05eb); | |
| 715 | − gjmp_addr(a); | |
| 716 | − } | |
| 717 | − vtop--; | |
| 718 | − } | |
| 699 | + int r = a - ind - 2; | |
| 700 | + if (r == (char)r) | |
| 701 | + g(op - 32), g(r); | |
| 702 | + else | |
| 703 | + g(0x0f), gjmp2(op - 16, r - 4); | |
| 719 | 704 | } |
| 705 | +#endif | |
| 720 | 706 | |
| 721 | −/* generate a test. set 'inv' to invert test. Stack entry is popped */ | |
| 722 | −ST_FUNC int gtst(int inv, int t) | |
| 707 | +ST_FUNC int gjmp_append(int n, int t) | |
| 723 | 708 | { |
| 724 | − int v = vtop->r & VT_VALMASK; | |
| 725 | − if (nocode_wanted) { | |
| 726 | − ; | |
| 727 | − } else if (v == VT_CMP) { | |
| 728 | − /* fast case : can jump directly since flags are set */ | |
| 729 | − g(0x0f); | |
| 730 | − t = gjmp2((vtop->c.i - 16) ^ inv, t); | |
| 731 | − } else if (v == VT_JMP || v == VT_JMPI) { | |
| 732 | − /* && or || optimization */ | |
| 733 | − if ((v & 1) == inv) { | |
| 734 | − /* insert vtop->c jump list in t */ | |
| 735 | − uint32_t n1, n = vtop->c.i; | |
| 736 | − if (n) { | |
| 737 | − while ((n1 = read32le(cur_text_section->data + n))) | |
| 738 | − n = n1; | |
| 739 | − write32le(cur_text_section->data + n, t); | |
| 740 | − t = vtop->c.i; | |
| 741 | − } | |
| 742 | − } else { | |
| 743 | − t = gjmp(t); | |
| 744 | − gsym(vtop->c.i); | |
| 745 | − } | |
| 709 | + void *p; | |
| 710 | + /* insert vtop->c jump list in t */ | |
| 711 | + if (n) { | |
| 712 | + uint32_t n1 = n, n2; | |
| 713 | + while ((n2 = read32le(p = cur_text_section->data + n1))) | |
| 714 | + n1 = n2; | |
| 715 | + write32le(p, t); | |
| 716 | + t = n; | |
| 746 | 717 | } |
| 747 | − vtop--; | |
| 748 | 718 | return t; |
| 749 | 719 | } |
| 750 | 720 | |
| 751 | −/* generate an integer binary operation */ | |
| 721 | +ST_FUNC int gjmp_cond(int op, int t) | |
| 722 | +{ | |
| 723 | + g(0x0f); | |
| 724 | + t = gjmp2(op - 16, t); | |
| 725 | + return t; | |
| 726 | +} | |
| 727 | + | |
| 752 | 728 | ST_FUNC void gen_opi(int op) |
| 753 | 729 | { |
| 754 | 730 | int r, fr, opc, c; |
| @@ -766,10 +742,9 @@ ST_FUNC void gen_opi(int op) · 11 unmodified lines | ||
| 766 | 742 | c = vtop->c.i; |
| 767 | 743 | if (c == (char)c) { |
| 768 | 744 | /* generate inc and dec for smaller code */ |
| 769 | − if (c==1 && opc==0 && op != TOK_ADDC1) { | |
| 770 | − o (0x40 | r); // inc | |
| 771 | − } else if (c==1 && opc==5 && op != TOK_SUBC1) { | |
| 772 | − o (0x48 | r); // dec | |
| 745 | + if ((c == 1 || c == -1) && (op == '+' || op == '-')) { | |
| 746 | + opc = (c == 1) ^ (op == '+'); | |
| 747 | + o (0x40 | (opc << 3) | r); // inc,dec | |
| 773 | 748 | } else { |
| 774 | 749 | o(0x83); |
| 775 | 750 | o(0xc0 | (opc << 3) | r); |
| @@ -787,10 +762,8 @@ ST_FUNC void gen_opi(int op) · 11 unmodified lines | ||
| 787 | 762 | o(0xc0 + r + fr * 8); |
| 788 | 763 | } |
| 789 | 764 | vtop--; |
| 790 | − if (op >= TOK_ULT && op <= TOK_GT) { | |
| 791 | − vtop->r = VT_CMP; | |
| 792 | − vtop->c.i = op; | |
| 793 | − } | |
| 765 | + if (op >= TOK_ULT && op <= TOK_GT) | |
| 766 | + vset_VT_CMP(op); | |
| 794 | 767 | break; |
| 795 | 768 | case '-': |
| 796 | 769 | case TOK_SUBC1: /* sub with carry generation */ |
| @@ -948,8 +921,7 @@ ST_FUNC void gen_opf(int op) · 151 unmodified lines | ||
| 948 | 921 | op = TOK_EQ; |
| 949 | 922 | } |
| 950 | 923 | vtop--; |
| 951 | − vtop->r = VT_CMP; | |
| 952 | − vtop->c.i = op; | |
| 924 | + vset_VT_CMP(op); | |
| 953 | 925 | } else { |
| 954 | 926 | /* no memory reference possible for long double operations */ |
| 955 | 927 | if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { |
| @@ -430,9 +430,15 @@ typedef struct SValue { · 429 unmodified lines | ||
| 430 | 430 | unsigned short r; /* register + flags */ |
| 431 | 431 | unsigned short r2; /* second register, used for 'long long' |
| 432 | 432 | type. If not used, set to VT_CONST */ |
| 433 | − CValue c; /* constant, if VT_CONST */ | |
| 434 | − struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if | |
| 435 | − result of unary() for an identifier. */ | |
| 433 | + union { | |
| 434 | + struct { int jtrue, jfalse; }; /* forward jmps */ | |
| 435 | + CValue c; /* constant, if VT_CONST */ | |
| 436 | + }; | |
| 437 | + union { | |
| 438 | + struct { unsigned short cmp_op, cmp_r; }; /* VT_CMP operation */ | |
| 439 | + struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if */ | |
| 440 | + }; /* result of unary() for an identifier. */ | |
| 441 | + | |
| 436 | 442 | } SValue; |
| 437 | 443 | |
| 438 | 444 | /* symbol attributes */ |
| @@ -1322,6 +1328,7 @@ ST_FUNC ElfSym *elfsym(Sym *); · 883 unmodified lines | ||
| 1322 | 1328 | ST_FUNC void update_storage(Sym *sym); |
| 1323 | 1329 | ST_FUNC Sym *external_global_sym(int v, CType *type); |
| 1324 | 1330 | ST_FUNC void vset(CType *type, int r, int v); |
| 1331 | +ST_FUNC void vset_VT_CMP(int op); | |
| 1325 | 1332 | ST_FUNC void vswap(void); |
| 1326 | 1333 | ST_FUNC void vpush_global_sym(CType *type, int v); |
| 1327 | 1334 | ST_FUNC void vrote(SValue *e, int n); |
| @@ -1490,12 +1497,8 @@ ST_FUNC void gfunc_epilog(void); · 162 unmodified lines | ||
| 1490 | 1497 | ST_FUNC void gen_fill_nops(int); |
| 1491 | 1498 | ST_FUNC int gjmp(int t); |
| 1492 | 1499 | ST_FUNC void gjmp_addr(int a); |
| 1493 | −ST_FUNC int gtst(int inv, int t); | |
| 1494 | −#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 | |
| 1495 | −ST_FUNC void gtst_addr(int inv, int a); | |
| 1496 | −#else | |
| 1497 | −#define gtst_addr(inv, a) gsym_addr(gtst(inv, 0), a) | |
| 1498 | −#endif | |
| 1500 | +ST_FUNC int gjmp_cond(int op, int t); | |
| 1501 | +ST_FUNC int gjmp_append(int n, int t); | |
| 1499 | 1502 | ST_FUNC void gen_opi(int op); |
| 1500 | 1503 | ST_FUNC void gen_opf(int op); |
| 1501 | 1504 | ST_FUNC void gen_cvt_ftoi(int t); |
| @@ -681,13 +681,8 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) · 680 unmodified lines | ||
| 681 | 681 | } |
| 682 | 682 | |
| 683 | 683 | /* ------------------------------------------------------------------------- */ |
| 684 | − | |
| 685 | −static void vsetc(CType *type, int r, CValue *vc) | |
| 684 | +static void vcheck_cmp(void) | |
| 686 | 685 | { |
| 687 | − int v; | |
| 688 | − | |
| 689 | − if (vtop >= vstack + (VSTACK_SIZE - 1)) | |
| 690 | − tcc_error("memory full (vstack)"); | |
| 691 | 686 | /* cannot let cpu flags if other instruction are generated. Also |
| 692 | 687 | avoid leaving VT_JMP anywhere except on the top of the stack |
| 693 | 688 | because it would complicate the code generator. |
| @@ -698,15 +693,17 @@ static void vsetc(CType *type, int r, CValue *vc) · 4 unmodified lines | ||
| 698 | 693 | as their value might still be used for real. All values |
| 699 | 694 | we push under nocode_wanted will eventually be popped |
| 700 | 695 | again, so that the VT_CMP/VT_JMP value will be in vtop |
| 701 | − when code is unsuppressed again. | |
| 696 | + when code is unsuppressed again. */ | |
| 702 | 697 | |
| 703 | − Same logic below in vswap(); */ | |
| 704 | − if (vtop >= vstack && !nocode_wanted) { | |
| 705 | − v = vtop->r & VT_VALMASK; | |
| 706 | − if (v == VT_CMP || (v & ~1) == VT_JMP) | |
| 707 | − gv(RC_INT); | |
| 708 | − } | |
| 698 | + if (vtop->r == VT_CMP && !nocode_wanted) | |
| 699 | + gv(RC_INT); | |
| 700 | +} | |
| 709 | 701 | |
| 702 | +static void vsetc(CType *type, int r, CValue *vc) | |
| 703 | +{ | |
| 704 | + if (vtop >= vstack + (VSTACK_SIZE - 1)) | |
| 705 | + tcc_error("memory full (vstack)"); | |
| 706 | + vcheck_cmp(); | |
| 710 | 707 | vtop++; |
| 711 | 708 | vtop->type = *type; |
| 712 | 709 | vtop->r = r; |
| @@ -718,12 +715,8 @@ static void vsetc(CType *type, int r, CValue *vc) · 5 unmodified lines | ||
| 718 | 715 | ST_FUNC void vswap(void) |
| 719 | 716 | { |
| 720 | 717 | SValue tmp; |
| 721 | − /* cannot vswap cpu flags. See comment at vsetc() above */ | |
| 722 | − if (vtop >= vstack && !nocode_wanted) { | |
| 723 | − int v = vtop->r & VT_VALMASK; | |
| 724 | − if (v == VT_CMP || (v & ~1) == VT_JMP) | |
| 725 | − gv(RC_INT); | |
| 726 | − } | |
| 718 | + | |
| 719 | + vcheck_cmp(); | |
| 727 | 720 | tmp = vtop[0]; |
| 728 | 721 | vtop[0] = vtop[-1]; |
| 729 | 722 | vtop[-1] = tmp; |
| @@ -740,9 +733,10 @@ ST_FUNC void vpop(void) · 10 unmodified lines | ||
| 740 | 733 | o(0xd8dd); /* fstp %st(0) */ |
| 741 | 734 | } else |
| 742 | 735 | #endif |
| 743 | − if (v == VT_JMP || v == VT_JMPI) { | |
| 736 | + if (v == VT_CMP) { | |
| 744 | 737 | /* need to put correct jump if && or || without test */ |
| 745 | − gsym(vtop->c.i); | |
| 738 | + gsym(vtop->jtrue); | |
| 739 | + gsym(vtop->jfalse); | |
| 746 | 740 | } |
| 747 | 741 | vtop--; |
| 748 | 742 | } |
| @@ -823,6 +817,7 @@ ST_FUNC void vrotb(int n) · 74 unmodified lines | ||
| 823 | 817 | int i; |
| 824 | 818 | SValue tmp; |
| 825 | 819 | |
| 820 | + vcheck_cmp(); | |
| 826 | 821 | tmp = vtop[-n + 1]; |
| 827 | 822 | for(i=-n+1;i!=0;i++) |
| 828 | 823 | vtop[i] = vtop[i+1]; |
| @@ -837,6 +832,7 @@ ST_FUNC void vrote(SValue *e, int n) · 8 unmodified lines | ||
| 837 | 832 | int i; |
| 838 | 833 | SValue tmp; |
| 839 | 834 | |
| 835 | + vcheck_cmp(); | |
| 840 | 836 | tmp = *e; |
| 841 | 837 | for(i = 0;i < n - 1; i++) |
| 842 | 838 | e[-i] = e[-i - 1]; |
| @@ -851,6 +847,75 @@ ST_FUNC void vrott(int n) · 8 unmodified lines | ||
| 851 | 847 | vrote(vtop, n); |
| 852 | 848 | } |
| 853 | 849 | |
| 850 | +/* ------------------------------------------------------------------------- */ | |
| 851 | +/* vtop->r = VT_CMP means CPU-flags have been set from comparison or test. */ | |
| 852 | + | |
| 853 | +/* called from generators to set the result from relational ops */ | |
| 854 | +ST_FUNC void vset_VT_CMP(int op) | |
| 855 | +{ | |
| 856 | + vtop->r = VT_CMP; | |
| 857 | + vtop->cmp_op = op; | |
| 858 | + vtop->jfalse = 0; | |
| 859 | + vtop->jtrue = 0; | |
| 860 | +} | |
| 861 | + | |
| 862 | +/* called once before asking generators to load VT_CMP to a register */ | |
| 863 | +static void vset_VT_JMP(void) | |
| 864 | +{ | |
| 865 | + int op = vtop->cmp_op; | |
| 866 | + if (vtop->jtrue || vtop->jfalse) { | |
| 867 | + /* we need to jump to 'mov $0,%R' or 'mov $1,%R' */ | |
| 868 | + int inv = op & (op < 2); /* small optimization */ | |
| 869 | + vseti(VT_JMP+inv, gvtst(inv, 0)); | |
| 870 | + } else { | |
| 871 | + /* otherwise convert flags (rsp. 0/1) to register */ | |
| 872 | + vtop->c.i = op; | |
| 873 | + if (op < 2) /* doesn't seem to happen */ | |
| 874 | + vtop->r = VT_CONST; | |
| 875 | + } | |
| 876 | +} | |
| 877 | + | |
| 878 | +/* Set CPU Flags, doesn't yet jump */ | |
| 879 | +static void gvtst_set(int inv, int t) | |
| 880 | +{ | |
| 881 | + int *p; | |
| 882 | + if (vtop->r != VT_CMP) { | |
| 883 | + vpushi(0); | |
| 884 | + gen_op(TOK_NE); | |
| 885 | + if (vtop->r != VT_CMP) /* must be VT_CONST then */ | |
| 886 | + vset_VT_CMP(vtop->c.i != 0); | |
| 887 | + } | |
| 888 | + p = inv ? &vtop->jfalse : &vtop->jtrue; | |
| 889 | + *p = gjmp_append(*p, t); | |
| 890 | +} | |
| 891 | + | |
| 892 | +/* Generate value test | |
| 893 | + * | |
| 894 | + * Generate a test for any value (jump, comparison and integers) */ | |
| 895 | +static int gvtst(int inv, int t) | |
| 896 | +{ | |
| 897 | + int op, u, x; | |
| 898 | + | |
| 899 | + gvtst_set(inv, t); | |
| 900 | + | |
| 901 | + t = vtop->jtrue, u = vtop->jfalse; | |
| 902 | + if (inv) | |
| 903 | + x = u, u = t, t = x; | |
| 904 | + op = vtop->cmp_op; | |
| 905 | + | |
| 906 | + /* jump to the wanted target */ | |
| 907 | + if (op > 1) | |
| 908 | + t = gjmp_cond(op ^ inv, t); | |
| 909 | + else if (op != inv) | |
| 910 | + t = gjmp(t); | |
| 911 | + /* resolve complementary jumps to here */ | |
| 912 | + gsym(u); | |
| 913 | + | |
| 914 | + vtop--; | |
| 915 | + return t; | |
| 916 | +} | |
| 917 | + | |
| 918 | +/* ------------------------------------------------------------------------- */ | |
| 854 | 919 | /* push a symbol value of TYPE */ |
| 855 | 920 | static inline void vpushsym(CType *type, Sym *sym) |
| 856 | 921 | { |
| @@ -1591,6 +1656,8 @@ ST_FUNC int gv(int rc) · 734 unmodified lines | ||
| 1591 | 1656 | /* restore wanted type */ |
| 1592 | 1657 | vtop->type.t = t1; |
| 1593 | 1658 | } else { |
| 1659 | + if (vtop->r == VT_CMP) | |
| 1660 | + vset_VT_JMP(); | |
| 1594 | 1661 | /* one register type load */ |
| 1595 | 1662 | load(r, vtop); |
| 1596 | 1663 | } |
| @@ -1608,13 +1675,10 @@ ST_FUNC int gv(int rc) · 11 unmodified lines | ||
| 1608 | 1675 | /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
| 1609 | 1676 | ST_FUNC void gv2(int rc1, int rc2) |
| 1610 | 1677 | { |
| 1611 | − int v; | |
| 1612 | − | |
| 1613 | 1678 | /* generate more generic register first. But VT_JMP or VT_CMP |
| 1614 | 1679 | values must be generated first in all cases to avoid possible |
| 1615 | 1680 | reload errors */ |
| 1616 | − v = vtop[0].r & VT_VALMASK; | |
| 1617 | − if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { | |
| 1681 | + if (vtop->r != VT_CMP && rc1 <= rc2) { | |
| 1618 | 1682 | vswap(); |
| 1619 | 1683 | gv(rc1); |
| 1620 | 1684 | vswap(); |
| @@ -1749,26 +1813,6 @@ static void gv_dup(void) · 128 unmodified lines | ||
| 1749 | 1813 | } |
| 1750 | 1814 | } |
| 1751 | 1815 | |
| 1752 | −/* Generate value test | |
| 1753 | − * | |
| 1754 | − * Generate a test for any value (jump, comparison and integers) */ | |
| 1755 | −ST_FUNC int gvtst(int inv, int t) | |
| 1756 | −{ | |
| 1757 | − int v = vtop->r & VT_VALMASK; | |
| 1758 | − if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) { | |
| 1759 | − vpushi(0); | |
| 1760 | − gen_op(TOK_NE); | |
| 1761 | − } | |
| 1762 | − if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { | |
| 1763 | − /* constant jmp optimization */ | |
| 1764 | − if ((vtop->c.i != 0) != inv) | |
| 1765 | − t = gjmp(t); | |
| 1766 | − vtop--; | |
| 1767 | − return t; | |
| 1768 | − } | |
| 1769 | − return gtst(inv, t); | |
| 1770 | −} | |
| 1771 | − | |
| 1772 | 1816 | #if PTR_SIZE == 4 |
| 1773 | 1817 | /* generate CPU independent (unsigned) long long operations */ |
| 1774 | 1818 | static void gen_opl(int op) |
| @@ -1974,8 +2018,8 @@ static void gen_opl(int op) · 199 unmodified lines | ||
| 1974 | 2018 | a = gvtst(1, 0); |
| 1975 | 2019 | if (op != TOK_EQ) { |
| 1976 | 2020 | /* generate non equal test */ |
| 1977 | − vpushi(TOK_NE); | |
| 1978 | − vtop->r = VT_CMP; | |
| 2021 | + vpushi(0); | |
| 2022 | + vset_VT_CMP(TOK_NE); | |
| 1979 | 2023 | b = gvtst(0, 0); |
| 1980 | 2024 | } |
| 1981 | 2025 | } |
| @@ -1990,9 +2034,12 @@ static void gen_opl(int op) · 8 unmodified lines | ||
| 1990 | 2034 | else if (op1 == TOK_GE) |
| 1991 | 2035 | op1 = TOK_UGE; |
| 1992 | 2036 | gen_op(op1); |
| 1993 | − a = gvtst(1, a); | |
| 1994 | − gsym(b); | |
| 1995 | − vseti(VT_JMPI, a); | |
| 2037 | +#if 0//def TCC_TARGET_I386 | |
| 2038 | + if (op == TOK_NE) { gsym(b); break; } | |
| 2039 | + if (op == TOK_EQ) { gsym(a); break; } | |
| 2040 | +#endif | |
| 2041 | + gvtst_set(1, a); | |
| 2042 | + gvtst_set(0, b); | |
| 1996 | 2043 | break; |
| 1997 | 2044 | } |
| 1998 | 2045 | } |
| @@ -5001,11 +5048,12 @@ ST_FUNC void unary(void) · 3002 unmodified lines | ||
| 5001 | 5048 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
| 5002 | 5049 | gen_cast_s(VT_BOOL); |
| 5003 | 5050 | vtop->c.i = !vtop->c.i; |
| 5004 | − } else if ((vtop->r & VT_VALMASK) == VT_CMP) | |
| 5005 | − vtop->c.i ^= 1; | |
| 5006 | − else { | |
| 5007 | − save_regs(1); | |
| 5008 | − vseti(VT_JMP, gvtst(1, 0)); | |
| 5051 | + } else if (vtop->r == VT_CMP) { | |
| 5052 | + vtop->cmp_op ^= 1; | |
| 5053 | + n = vtop->jfalse, vtop->jfalse = vtop->jtrue, vtop->jtrue = n; | |
| 5054 | + } else { | |
| 5055 | + vpushi(0); | |
| 5056 | + gen_op(TOK_EQ); | |
| 5009 | 5057 | } |
| 5010 | 5058 | break; |
| 5011 | 5059 | case '~': |
| @@ -5035,7 +5083,9 @@ ST_FUNC void unary(void) · 23 unmodified lines | ||
| 5035 | 5083 | next(); |
| 5036 | 5084 | in_sizeof++; |
| 5037 | 5085 | expr_type(&type, unary); /* Perform a in_sizeof = 0; */ |
| 5038 | − s = vtop[1].sym; /* hack: accessing previous vtop */ | |
| 5086 | + s = NULL; | |
| 5087 | + if (vtop[1].r & VT_SYM) | |
| 5088 | + s = vtop[1].sym; /* hack: accessing previous vtop */ | |
| 5039 | 5089 | size = type_size(&type, &align); |
| 5040 | 5090 | if (s && s->a.aligned) |
| 5041 | 5091 | align = 1 << (s->a.aligned - 1); |
| @@ -5653,7 +5703,7 @@ static void expr_landor(void(*e_fn)(void), int e_op, int i) · 611 unmodified lines | ||
| 5653 | 5703 | gsym(t); |
| 5654 | 5704 | nocode_wanted -= f; |
| 5655 | 5705 | } else { |
| 5656 | − vseti(VT_JMP + i, gvtst(i, t)); | |
| 5706 | + gvtst_set(i, t); | |
| 5657 | 5707 | } |
| 5658 | 5708 | break; |
| 5659 | 5709 | } |
| @@ -5696,6 +5746,16 @@ static int condition_3way(void) · 36 unmodified lines | ||
| 5696 | 5746 | return c; |
| 5697 | 5747 | } |
| 5698 | 5748 | |
| 5749 | +static int is_cond_bool(SValue *sv) | |
| 5750 | +{ | |
| 5751 | + if ((sv->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST | |
| 5752 | + && (sv->type.t & VT_BTYPE) == VT_INT) | |
| 5753 | + return (unsigned)sv->c.i < 2; | |
| 5754 | + if (sv->r == VT_CMP) | |
| 5755 | + return 1; | |
| 5756 | + return 0; | |
| 5757 | +} | |
| 5758 | + | |
| 5699 | 5759 | static void expr_cond(void) |
| 5700 | 5760 | { |
| 5701 | 5761 | int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g; |
| @@ -5741,6 +5801,12 @@ static void expr_cond(void) · 39 unmodified lines | ||
| 5741 | 5801 | if (!g) |
| 5742 | 5802 | gexpr(); |
| 5743 | 5803 | |
| 5804 | + if (c < 0 && vtop->r == VT_CMP) { | |
| 5805 | + t1 = gvtst(0, 0); | |
| 5806 | + vpushi(0); | |
| 5807 | + gvtst_set(0, t1); | |
| 5808 | + } | |
| 5809 | + | |
| 5744 | 5810 | if ((vtop->type.t & VT_BTYPE) == VT_FUNC) |
| 5745 | 5811 | mk_pointer(&vtop->type); |
| 5746 | 5812 | type1 = vtop->type; |
| @@ -5761,6 +5827,22 @@ static void expr_cond(void) · 14 unmodified lines | ||
| 5761 | 5827 | skip(':'); |
| 5762 | 5828 | expr_cond(); |
| 5763 | 5829 | |
| 5830 | + if (c < 0 && is_cond_bool(vtop) && is_cond_bool(&sv)) { | |
| 5831 | + if (sv.r == VT_CMP) { | |
| 5832 | + t1 = sv.jtrue; | |
| 5833 | + t2 = u; | |
| 5834 | + } else { | |
| 5835 | + t1 = gvtst(0, 0); | |
| 5836 | + t2 = gjmp(0); | |
| 5837 | + gsym(u); | |
| 5838 | + vpushv(&sv); | |
| 5839 | + } | |
| 5840 | + gvtst_set(0, t1); | |
| 5841 | + gvtst_set(1, t2); | |
| 5842 | + nocode_wanted = ncw_prev; | |
| 5843 | + // tcc_warning("two conditions expr_cond"); | |
| 5844 | + return; | |
| 5845 | + } | |
| 5764 | 5846 | |
| 5765 | 5847 | if ((vtop->type.t & VT_BTYPE) == VT_FUNC) |
| 5766 | 5848 | mk_pointer(&vtop->type); |
| @@ -6059,12 +6141,16 @@ static int case_cmp(const void *pa, const void *pb) · 292 unmodified lines | ||
| 6059 | 6141 | return a < b ? -1 : a > b; |
| 6060 | 6142 | } |
| 6061 | 6143 | |
| 6144 | +static void gtst_addr(int t, int a) | |
| 6145 | +{ | |
| 6146 | + gsym_addr(gvtst(0, t), a); | |
| 6147 | +} | |
| 6148 | + | |
| 6062 | 6149 | static void gcase(struct case_t **base, int len, int *bsym) |
| 6063 | 6150 | { |
| 6064 | 6151 | struct case_t *p; |
| 6065 | 6152 | int e; |
| 6066 | 6153 | int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG; |
| 6067 | − gv(RC_INT); | |
| 6068 | 6154 | while (len > 4) { |
| 6069 | 6155 | /* binary search */ |
| 6070 | 6156 | p = base[len/2]; |
| @@ -6074,7 +6160,7 @@ static void gcase(struct case_t **base, int len, int *bsym) · 3 unmodified lines | ||
| 6074 | 6160 | else |
| 6075 | 6161 | vpushi(p->v2); |
| 6076 | 6162 | gen_op(TOK_LE); |
| 6077 | − e = gtst(1, 0); | |
| 6163 | + e = gvtst(1, 0); | |
| 6078 | 6164 | vdup(); |
| 6079 | 6165 | if (ll) |
| 6080 | 6166 | vpushll(p->v1); |
| @@ -6084,10 +6170,6 @@ static void gcase(struct case_t **base, int len, int *bsym) · 3 unmodified lines | ||
| 6084 | 6170 | gtst_addr(0, p->sym); /* v1 <= x <= v2 */ |
| 6085 | 6171 | /* x < v1 */ |
| 6086 | 6172 | gcase(base, len/2, bsym); |
| 6087 | − if (cur_switch->def_sym) | |
| 6088 | − gjmp_addr(cur_switch->def_sym); | |
| 6089 | − else | |
| 6090 | − *bsym = gjmp(*bsym); | |
| 6091 | 6173 | /* x > v2 */ |
| 6092 | 6174 | gsym(e); |
| 6093 | 6175 | e = len/2 + 1; |
| @@ -6106,7 +6188,7 @@ static void gcase(struct case_t **base, int len, int *bsym) · 12 unmodified lines | ||
| 6106 | 6188 | gtst_addr(0, p->sym); |
| 6107 | 6189 | } else { |
| 6108 | 6190 | gen_op(TOK_LE); |
| 6109 | − e = gtst(1, 0); | |
| 6191 | + e = gvtst(1, 0); | |
| 6110 | 6192 | vdup(); |
| 6111 | 6193 | if (ll) |
| 6112 | 6194 | vpushll(p->v1); |
| @@ -6117,6 +6199,7 @@ static void gcase(struct case_t **base, int len, int *bsym) · 4 unmodified lines | ||
| 6117 | 6199 | gsym(e); |
| 6118 | 6200 | } |
| 6119 | 6201 | } |
| 6202 | + *bsym = gjmp(*bsym); | |
| 6120 | 6203 | } |
| 6121 | 6204 | |
| 6122 | 6205 | /* call 'func' for each __attribute__((cleanup(func))) */ |
| @@ -6367,15 +6450,17 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr) · 244 unmodified lines | ||
| 6367 | 6450 | gexpr(); |
| 6368 | 6451 | skip(')'); |
| 6369 | 6452 | switchval = *vtop--; |
| 6370 | − a = 0; | |
| 6371 | − b = gjmp(0); /* jump to first case */ | |
| 6453 | + | |
| 6372 | 6454 | sw.p = NULL; sw.n = 0; sw.def_sym = 0; |
| 6373 | 6455 | saved = cur_switch; |
| 6374 | 6456 | cur_switch = &sw; |
| 6457 | + a = 0; | |
| 6458 | + b = gjmp(0); /* jump to first case */ | |
| 6375 | 6459 | block(&a, current_cleanups, csym, ccl, 0); |
| 6376 | 6460 | a = gjmp(a); /* add implicit break */ |
| 6377 | 6461 | /* case lookup */ |
| 6378 | 6462 | gsym(b); |
| 6463 | + | |
| 6379 | 6464 | qsort(sw.p, sw.n, sizeof(void*), case_cmp); |
| 6380 | 6465 | for (b = 1; b < sw.n; b++) |
| 6381 | 6466 | if (sw.p[b - 1]->v2 >= sw.p[b]->v1) |
| @@ -6385,14 +6470,17 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr) · 3 unmodified lines | ||
| 6385 | 6470 | if ((switchval.type.t & VT_BTYPE) == VT_LLONG) |
| 6386 | 6471 | switchval.type.t &= ~VT_UNSIGNED; |
| 6387 | 6472 | vpushv(&switchval); |
| 6388 | − gcase(sw.p, sw.n, &a); | |
| 6473 | + gv(RC_INT); | |
| 6474 | + d = 0, gcase(sw.p, sw.n, &d); | |
| 6389 | 6475 | vpop(); |
| 6390 | 6476 | if (sw.def_sym) |
| 6391 | − gjmp_addr(sw.def_sym); | |
| 6392 | − dynarray_reset(&sw.p, &sw.n); | |
| 6393 | − cur_switch = saved; | |
| 6477 | + gsym_addr(d, sw.def_sym); | |
| 6478 | + else | |
| 6479 | + gsym(d); | |
| 6394 | 6480 | /* break label */ |
| 6395 | 6481 | gsym(a); |
| 6482 | + dynarray_reset(&sw.p, &sw.n); | |
| 6483 | + cur_switch = saved; | |
| 6396 | 6484 | |
| 6397 | 6485 | } else if (t == TOK_CASE) { |
| 6398 | 6486 | struct case_t *cr = tcc_malloc(sizeof(struct case_t)); |
| @@ -3777,6 +3777,7 @@ void math_cmp_test(void) · 3776 unmodified lines | ||
| 3777 | 3777 | double one = 1.0; |
| 3778 | 3778 | double two = 2.0; |
| 3779 | 3779 | int comp = 0; |
| 3780 | + int v; | |
| 3780 | 3781 | #define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part) |
| 3781 | 3782 | |
| 3782 | 3783 | /* This asserts that "a op b" is _not_ true, but "a iop b" is true. |
| @@ -3798,7 +3799,8 @@ void math_cmp_test(void) · 15 unmodified lines | ||
| 3798 | 3799 | if ((a iop b) || comp) \ |
| 3799 | 3800 | ; \ |
| 3800 | 3801 | else \ |
| 3801 | − bug (a,b,op,iop,5); | |
| 3802 | + bug (a,b,op,iop,5); \ | |
| 3803 | + if (v = !(a op b), !v) bug(a,b,op,iop,7); | |
| 3802 | 3804 | |
| 3803 | 3805 | /* Equality tests. */ |
| 3804 | 3806 | FCMP(nan, nan, ==, !=, 0); |
| @@ -471,22 +471,22 @@ void load(int r, SValue *sv) · 470 unmodified lines | ||
| 471 | 471 | orex(1,0,r,0x8d); /* lea xxx(%ebp), r */ |
| 472 | 472 | gen_modrm(r, VT_LOCAL, sv->sym, fc); |
| 473 | 473 | } else if (v == VT_CMP) { |
| 474 | − orex(0,r,0,0); | |
| 475 | − if ((fc & ~0x100) != TOK_NE) | |
| 476 | − oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */ | |
| 477 | − else | |
| 478 | − oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */ | |
| 479 | 474 | if (fc & 0x100) |
| 480 | 475 | { |
| 476 | + v = vtop->cmp_r; | |
| 477 | + fc &= ~0x100; | |
| 481 | 478 | /* This was a float compare. If the parity bit is |
| 482 | 479 | set the result was unordered, meaning false for everything |
| 483 | 480 | except TOK_NE, and true for TOK_NE. */ |
| 484 | − fc &= ~0x100; | |
| 485 | − o(0x037a + (REX_BASE(r) << 8)); | |
| 486 | − } | |
| 481 | + orex(0, r, 0, 0xb0 + REG_VALUE(r)); /* mov $0/1,%al */ | |
| 482 | + g(v ^ fc ^ (v == TOK_NE)); | |
| 483 | + o(0x037a + (REX_BASE(r) << 8)); | |
| 484 | + } | |
| 487 | 485 | orex(0,r,0, 0x0f); /* setxx %br */ |
| 488 | 486 | o(fc); |
| 489 | 487 | o(0xc0 + REG_VALUE(r)); |
| 488 | + orex(0,r,0, 0x0f); | |
| 489 | + o(0xc0b6 + REG_VALUE(r) * 0x900); /* movzbl %al, %eax */ | |
| 490 | 490 | } else if (v == VT_JMP || v == VT_JMPI) { |
| 491 | 491 | t = v & 1; |
| 492 | 492 | orex(0,r,0,0); |
| @@ -1666,42 +1666,23 @@ void gjmp_addr(int a) · 1173 unmodified lines | ||
| 1666 | 1666 | } |
| 1667 | 1667 | } |
| 1668 | 1668 | |
| 1669 | −ST_FUNC void gtst_addr(int inv, int a) | |
| 1669 | +ST_FUNC int gjmp_append(int n, int t) | |
| 1670 | 1670 | { |
| 1671 | − int v = vtop->r & VT_VALMASK; | |
| 1672 | − if (v == VT_CMP) { | |
| 1673 | − inv ^= (vtop--)->c.i; | |
| 1674 | − a -= ind + 2; | |
| 1675 | − if (a == (char)a) { | |
| 1676 | − g(inv - 32); | |
| 1677 | − g(a); | |
| 1678 | − } else { | |
| 1679 | − g(0x0f); | |
| 1680 | − oad(inv - 16, a - 4); | |
| 1681 | − } | |
| 1682 | − } else if ((v & ~1) == VT_JMP) { | |
| 1683 | − if ((v & 1) != inv) { | |
| 1684 | − gjmp_addr(a); | |
| 1685 | − gsym(vtop->c.i); | |
| 1686 | − } else { | |
| 1687 | − gsym(vtop->c.i); | |
| 1688 | − o(0x05eb); | |
| 1689 | − gjmp_addr(a); | |
| 1690 | − } | |
| 1691 | − vtop--; | |
| 1671 | + void *p; | |
| 1672 | + /* insert vtop->c jump list in t */ | |
| 1673 | + if (n) { | |
| 1674 | + uint32_t n1 = n, n2; | |
| 1675 | + while ((n2 = read32le(p = cur_text_section->data + n1))) | |
| 1676 | + n1 = n2; | |
| 1677 | + write32le(p, t); | |
| 1678 | + t = n; | |
| 1692 | 1679 | } |
| 1680 | + return t; | |
| 1693 | 1681 | } |
| 1694 | 1682 | |
| 1695 | −/* generate a test. set 'inv' to invert test. Stack entry is popped */ | |
| 1696 | −ST_FUNC int gtst(int inv, int t) | |
| 1683 | +ST_FUNC int gjmp_cond(int op, int t) | |
| 1697 | 1684 | { |
| 1698 | − int v = vtop->r & VT_VALMASK; | |
| 1699 | − | |
| 1700 | − if (nocode_wanted) { | |
| 1701 | − ; | |
| 1702 | − } else if (v == VT_CMP) { | |
| 1703 | − /* fast case : can jump directly since flags are set */ | |
| 1704 | − if (vtop->c.i & 0x100) | |
| 1685 | + if (op & 0x100) | |
| 1705 | 1686 | { |
| 1706 | 1687 | /* This was a float compare. If the parity flag is set |
| 1707 | 1688 | the result was unordered. For anything except != this |
| @@ -1710,9 +1691,10 @@ ST_FUNC int gtst(int inv, int t) · 2 unmodified lines | ||
| 1710 | 1691 | Take care about inverting the test. We need to jump |
| 1711 | 1692 | to our target if the result was unordered and test wasn't NE, |
| 1712 | 1693 | otherwise if unordered we don't want to jump. */ |
| 1713 | − vtop->c.i &= ~0x100; | |
| 1714 | − if (inv == (vtop->c.i == TOK_NE)) | |
| 1715 | − o(0x067a); /* jp +6 */ | |
| 1694 | + int v = vtop->cmp_r; | |
| 1695 | + op &= ~0x100; | |
| 1696 | + if (op ^ v ^ (v != TOK_NE)) | |
| 1697 | + o(0x067a); /* jp +6 */ | |
| 1716 | 1698 | else |
| 1717 | 1699 | { |
| 1718 | 1700 | g(0x0f); |
| @@ -1720,25 +1702,8 @@ ST_FUNC int gtst(int inv, int t) · 1 unmodified line | ||
| 1720 | 1702 | } |
| 1721 | 1703 | } |
| 1722 | 1704 | g(0x0f); |
| 1723 | − t = gjmp2((vtop->c.i - 16) ^ inv, t); | |
| 1724 | − } else if (v == VT_JMP || v == VT_JMPI) { | |
| 1725 | − /* && or || optimization */ | |
| 1726 | − if ((v & 1) == inv) { | |
| 1727 | − /* insert vtop->c jump list in t */ | |
| 1728 | − uint32_t n1, n = vtop->c.i; | |
| 1729 | − if (n) { | |
| 1730 | − while ((n1 = read32le(cur_text_section->data + n))) | |
| 1731 | − n = n1; | |
| 1732 | − write32le(cur_text_section->data + n, t); | |
| 1733 | − t = vtop->c.i; | |
| 1734 | − } | |
| 1735 | − } else { | |
| 1736 | − t = gjmp(t); | |
| 1737 | − gsym(vtop->c.i); | |
| 1738 | − } | |
| 1739 | − } | |
| 1740 | − vtop--; | |
| 1741 | − return t; | |
| 1705 | + t = gjmp2(op - 16, t); | |
| 1706 | + return t; | |
| 1742 | 1707 | } |
| 1743 | 1708 | |
| 1744 | 1709 | /* generate an integer binary operation */ |
| @@ -1779,10 +1744,8 @@ void gen_opi(int op) · 34 unmodified lines | ||
| 1779 | 1744 | o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8); |
| 1780 | 1745 | } |
| 1781 | 1746 | vtop--; |
| 1782 | − if (op >= TOK_ULT && op <= TOK_GT) { | |
| 1783 | − vtop->r = VT_CMP; | |
| 1784 | − vtop->c.i = op; | |
| 1785 | − } | |
| 1747 | + if (op >= TOK_ULT && op <= TOK_GT) | |
| 1748 | + vset_VT_CMP(op); | |
| 1786 | 1749 | break; |
| 1787 | 1750 | case '-': |
| 1788 | 1751 | case TOK_SUBC1: /* sub with carry generation */ |
| @@ -1937,8 +1900,7 @@ void gen_opf(int op) · 148 unmodified lines | ||
| 1937 | 1900 | op = TOK_EQ; |
| 1938 | 1901 | } |
| 1939 | 1902 | vtop--; |
| 1940 | − vtop->r = VT_CMP; | |
| 1941 | − vtop->c.i = op; | |
| 1903 | + vset_VT_CMP(op); | |
| 1942 | 1904 | } else { |
| 1943 | 1905 | /* no memory reference possible for long double operations */ |
| 1944 | 1906 | load(TREG_ST0, vtop); |
| @@ -2016,8 +1978,8 @@ void gen_opf(int op) · 71 unmodified lines | ||
| 2016 | 1978 | } |
| 2017 | 1979 | |
| 2018 | 1980 | vtop--; |
| 2019 | − vtop->r = VT_CMP; | |
| 2020 | − vtop->c.i = op | 0x100; | |
| 1981 | + vset_VT_CMP(op | 0x100); | |
| 1982 | + vtop->cmp_r = op; | |
| 2021 | 1983 | } else { |
| 2022 | 1984 | assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE); |
| 2023 | 1985 | switch(op) { |