History

jump optimizations

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: ...

grischka committed 7 years ago

Commit 8227db31 parent 1b575609 files · +346 −283Browse files

Unified · Split

9 files
  1. Makefile +1 −1
  2. arm-gen.c +30 −47
  3. arm64-gen.c +63 −2
  4. c67-gen.c +16 −24
  5. i386-gen.c +32 −60
  6. tcc.h +12 −9
  7. tccgen.c +158 −70
  8. tests/tcctest.c +3 −1
  9. x86_64-gen.c +31 −69
Makefile+1−1
@@ -125,7 +125,7 @@ DEF-i386-win32 = -DTCC_TARGET_PE -DTCC_TARGET_I386 · 124 unmodified lines
125125 DEF-x86_64-win32= -DTCC_TARGET_PE -DTCC_TARGET_X86_64
126126 DEF-x86_64-osx = -DTCC_TARGET_MACHO -DTCC_TARGET_X86_64
127127 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
129129 DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
130130 DEF-arm-fpa = -DTCC_TARGET_ARM
131131 DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
arm-gen.c+30−47
@@ -1419,7 +1419,7 @@ ST_FUNC void gen_fill_nops(int bytes) · 1418 unmodified lines
14191419 }
14201420
14211421 /* generate a jump to a label */
1422−int gjmp(int t)
1422+ST_FUNC int gjmp(int t)
14231423 {
14241424 int r;
14251425 if (nocode_wanted)
@@ -1430,51 +1430,37 @@ int gjmp(int t) · 4 unmodified lines
14301430 }
14311431
14321432 /* generate a jump to a fixed address */
1433−void gjmp_addr(int a)
1433+ST_FUNC void gjmp_addr(int a)
14341434 {
14351435 gjmp(a);
14361436 }
14371437
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)
14401439 {
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;
14451443 r=ind;
1444+ op=mapcc(op);
1445+ op|=encbranch(r,t,1);
1446+ o(op);
1447+ return r;
1448+}
14461449
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;
14761463 }
1477− vtop--;
14781464 return t;
14791465 }
14801466
@@ -1611,10 +1597,8 @@ void gen_opi(int op) · 130 unmodified lines
16111597 o(opc|(r<<12)|fr);
16121598 done:
16131599 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);
16181602 break;
16191603 case 2:
16201604 opc=0xE1A00000|(opc<<5);
@@ -1730,9 +1714,7 @@ void gen_opf(int op) · 109 unmodified lines
17301714 case TOK_UGE: op=TOK_GE; break;
17311715 case TOK_UGT: op=TOK_GT; break;
17321716 }
1733−
1734− vtop->r = VT_CMP;
1735− vtop->c.i = op;
1717+ vset_VT_CMP(op);
17361718 return;
17371719 }
17381720 r=gv(RC_FLOAT);
@@ -1934,8 +1916,9 @@ void gen_opf(int op) · 195 unmodified lines
19341916 } else {
19351917 r2=fpr(gv(RC_FLOAT));
19361918 }
1937− vtop[-1].r = VT_CMP;
1938− vtop[-1].c.i = op;
1919+ --vtop;
1920+ vset_VT_CMP(op);
1921+ ++vtop;
19391922 } else {
19401923 tcc_error("unknown fp op %x!",op);
19411924 return;
arm64-gen.c+63−2
@@ -91,6 +91,9 @@ static uint32_t fltr(int r) · 90 unmodified lines
9191 return r - TREG_F(0);
9292 }
9393
94+#define dprintf(x) ((void)(tcc_state->verbose == 2 && printf x))
95+//#define dprintf(x)
96+
9497 // Add an instruction to text section:
9598 ST_FUNC void o(unsigned int c)
9699 {
@@ -100,6 +103,7 @@ ST_FUNC void o(unsigned int c) · 3 unmodified lines
100103 if (ind1 > cur_text_section->data_allocated)
101104 section_realloc(cur_text_section, ind1);
102105 write32le(cur_text_section->data + ind, c);
106+ dprintf(("o %04x : %08x\n", ind, c)); //gr
103107 ind = ind1;
104108 }
105109
@@ -232,6 +236,7 @@ ST_FUNC void gsym_addr(int t_, int a_) · 126 unmodified lines
232236 tcc_error("branch out of range");
233237 write32le(ptr, (a - t == 4 ? 0xd503201f : // nop
234238 0x14000000 | ((a - t) >> 2 & 0x3ffffff))); // b
239+ dprintf((". gsym TARG=%04x ADDR=%04x\n", t, a)); //gr
235240 t = next;
236241 }
237242 }
@@ -440,6 +445,8 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend) · 202 unmodified lines
440445 }
441446 }
442447
448+static void arm64_load_cmp(int r, SValue *sv);
449+
443450 ST_FUNC void load(int r, SValue *sv)
444451 {
445452 int svtt = sv->type.t;
@@ -531,6 +538,11 @@ ST_FUNC void load(int r, SValue *sv) · 85 unmodified lines
531538 return;
532539 }
533540
541+ if (svr == VT_CMP) {
542+ arm64_load_cmp(r, sv);
543+ return;
544+ }
545+
534546 printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul);
535547 assert(0);
536548 }
@@ -1284,6 +1296,7 @@ ST_FUNC void gen_fill_nops(int bytes) · 747 unmodified lines
12841296 ST_FUNC int gjmp(int t)
12851297 {
12861298 int r = ind;
1299+ dprintf((". gjmp T=%04x\n", t)); //gr
12871300 if (nocode_wanted)
12881301 return t;
12891302 o(t);
@@ -1295,11 +1308,57 @@ ST_FUNC void gjmp_addr(int a) · 5 unmodified lines
12951308 {
12961309 assert(a - ind + 0x8000000 < 0x10000000);
12971310 o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
1311+ dprintf((". gjmp_addr T=%04x\n", a)); //gr
12981312 }
12991313
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)
13011355 {
13021356 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+
13031362 if (bt == VT_LDOUBLE) {
13041363 uint32_t a, b, f = fltr(gv(RC_FLOAT));
13051364 a = get_reg(RC_INT);
@@ -1324,7 +1383,6 @@ ST_FUNC int gtst(int inv, int t) · 18 unmodified lines
13241383 uint32_t a = intr(gv(RC_INT));
13251384 o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8
13261385 }
1327− --vtop;
13281386 return gjmp(t);
13291387 }
13301388
@@ -1553,11 +1611,13 @@ static void arm64_gen_opil(int op, uint32_t l) · 222 unmodified lines
15531611 ST_FUNC void gen_opi(int op)
15541612 {
15551613 arm64_gen_opil(op, 0);
1614+ arm64_vset_VT_CMP(op);
15561615 }
15571616
15581617 ST_FUNC void gen_opl(int op)
15591618 {
15601619 arm64_gen_opil(op, 1);
1620+ arm64_vset_VT_CMP(op);
15611621 }
15621622
15631623 ST_FUNC void gen_opf(int op)
@@ -1657,6 +1717,7 @@ ST_FUNC void gen_opf(int op) · 93 unmodified lines
16571717 default:
16581718 assert(0);
16591719 }
1720+ arm64_vset_VT_CMP(op);
16601721 }
16611722
16621723 // Generate sign extension from 32 to 64 bits:
c67-gen.c+16−24
@@ -2072,15 +2072,13 @@ void gjmp_addr(int a) · 2071 unmodified lines
20722072 }
20732073
20742074 /* 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)
20762076 {
2077− int ind1, n;
2078− int v, *p;
2077+ int ind1;
2078+ int inv = op & 1;
2079+ if (nocode_wanted)
2080+ return t;
20792081
2080− v = vtop->r & VT_VALMASK;
2081− if (nocode_wanted) {
2082− ;
2083− } else if (v == VT_CMP) {
20842082 /* fast case : can jump directly since flags are set */
20852083 // C67 uses B2 sort of as flags register
20862084 ind1 = ind;
@@ -2098,16 +2096,18 @@ int gtst(int inv, int t) · 11 unmodified lines
20982096 C67_NOP(5);
20992097 t = ind1; //return where we need to patch
21002098
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;
21042106 /* insert vtop->c jump list in t */
21052107
21062108 // I guess the idea is to traverse to the
21072109 // null at the end of the list and store t
21082110 // there
2109−
2110− n = vtop->c.i;
21112111 while (n != 0) {
21122112 p = (int *) (cur_text_section->data + n);
21132113
@@ -2117,14 +2117,8 @@ int gtst(int inv, int t) · 3 unmodified lines
21172117 }
21182118 *p |= (t & 0xffff) << 7;
21192119 *(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;
21262121 }
2127− vtop--;
21282122 return t;
21292123 }
21302124
@@ -2200,10 +2194,8 @@ void gen_opi(int op) · 69 unmodified lines
22002194 ALWAYS_ASSERT(FALSE);
22012195
22022196 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);
22072199 break;
22082200 case '-':
22092201 case TOK_SUBC1: /* sub with carry generation */
@@ -2359,7 +2351,7 @@ void gen_opf(int op) · 149 unmodified lines
23592351 } else {
23602352 ALWAYS_ASSERT(FALSE);
23612353 }
2362− vtop->r = VT_CMP; // tell TCC that result is in "flags" actually B2
2354+ vset_VT_CMP(0x80);
23632355 } else {
23642356 if (op == '+') {
23652357 if ((ft & VT_BTYPE) == VT_DOUBLE) {
i386-gen.c+32−60
@@ -261,10 +261,10 @@ ST_FUNC void load(int r, SValue *sv) · 260 unmodified lines
261261 o(0xe8 + r); /* mov %ebp, r */
262262 }
263263 } else if (v == VT_CMP) {
264− oad(0xb8 + r, 0); /* mov $0, r */
265264 o(0x0f); /* setxx %br */
266265 o(fc);
267266 o(0xc0 + r);
267+ o(0xc0b60f + r * 0x90000); /* movzbl %al, %eax */
268268 } else if (v == VT_JMP || v == VT_JMPI) {
269269 t = v & 1;
270270 oad(0xb8 + r, t); /* mov $1, r */
@@ -692,63 +692,39 @@ ST_FUNC void gjmp_addr(int a) · 421 unmodified lines
692692 }
693693 }
694694
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)
696698 {
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);
719704 }
705+#endif
720706
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)
723708 {
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;
746717 }
747− vtop--;
748718 return t;
749719 }
750720
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+
752728 ST_FUNC void gen_opi(int op)
753729 {
754730 int r, fr, opc, c;
@@ -766,10 +742,9 @@ ST_FUNC void gen_opi(int op) · 11 unmodified lines
766742 c = vtop->c.i;
767743 if (c == (char)c) {
768744 /* 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
773748 } else {
774749 o(0x83);
775750 o(0xc0 | (opc << 3) | r);
@@ -787,10 +762,8 @@ ST_FUNC void gen_opi(int op) · 11 unmodified lines
787762 o(0xc0 + r + fr * 8);
788763 }
789764 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);
794767 break;
795768 case '-':
796769 case TOK_SUBC1: /* sub with carry generation */
@@ -948,8 +921,7 @@ ST_FUNC void gen_opf(int op) · 151 unmodified lines
948921 op = TOK_EQ;
949922 }
950923 vtop--;
951− vtop->r = VT_CMP;
952− vtop->c.i = op;
924+ vset_VT_CMP(op);
953925 } else {
954926 /* no memory reference possible for long double operations */
955927 if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
tcc.h+12−9
@@ -430,9 +430,15 @@ typedef struct SValue { · 429 unmodified lines
430430 unsigned short r; /* register + flags */
431431 unsigned short r2; /* second register, used for 'long long'
432432 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+
436442 } SValue;
437443
438444 /* symbol attributes */
@@ -1322,6 +1328,7 @@ ST_FUNC ElfSym *elfsym(Sym *); · 883 unmodified lines
13221328 ST_FUNC void update_storage(Sym *sym);
13231329 ST_FUNC Sym *external_global_sym(int v, CType *type);
13241330 ST_FUNC void vset(CType *type, int r, int v);
1331+ST_FUNC void vset_VT_CMP(int op);
13251332 ST_FUNC void vswap(void);
13261333 ST_FUNC void vpush_global_sym(CType *type, int v);
13271334 ST_FUNC void vrote(SValue *e, int n);
@@ -1490,12 +1497,8 @@ ST_FUNC void gfunc_epilog(void); · 162 unmodified lines
14901497 ST_FUNC void gen_fill_nops(int);
14911498 ST_FUNC int gjmp(int t);
14921499 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);
14991502 ST_FUNC void gen_opi(int op);
15001503 ST_FUNC void gen_opf(int op);
15011504 ST_FUNC void gen_cvt_ftoi(int t);
tccgen.c+158−70
@@ -681,13 +681,8 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) · 680 unmodified lines
681681 }
682682
683683 /* ------------------------------------------------------------------------- */
684−
685−static void vsetc(CType *type, int r, CValue *vc)
684+static void vcheck_cmp(void)
686685 {
687− int v;
688−
689− if (vtop >= vstack + (VSTACK_SIZE - 1))
690− tcc_error("memory full (vstack)");
691686 /* cannot let cpu flags if other instruction are generated. Also
692687 avoid leaving VT_JMP anywhere except on the top of the stack
693688 because it would complicate the code generator.
@@ -698,15 +693,17 @@ static void vsetc(CType *type, int r, CValue *vc) · 4 unmodified lines
698693 as their value might still be used for real. All values
699694 we push under nocode_wanted will eventually be popped
700695 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. */
702697
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+}
709701
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();
710707 vtop++;
711708 vtop->type = *type;
712709 vtop->r = r;
@@ -718,12 +715,8 @@ static void vsetc(CType *type, int r, CValue *vc) · 5 unmodified lines
718715 ST_FUNC void vswap(void)
719716 {
720717 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();
727720 tmp = vtop[0];
728721 vtop[0] = vtop[-1];
729722 vtop[-1] = tmp;
@@ -740,9 +733,10 @@ ST_FUNC void vpop(void) · 10 unmodified lines
740733 o(0xd8dd); /* fstp %st(0) */
741734 } else
742735 #endif
743− if (v == VT_JMP || v == VT_JMPI) {
736+ if (v == VT_CMP) {
744737 /* need to put correct jump if && or || without test */
745− gsym(vtop->c.i);
738+ gsym(vtop->jtrue);
739+ gsym(vtop->jfalse);
746740 }
747741 vtop--;
748742 }
@@ -823,6 +817,7 @@ ST_FUNC void vrotb(int n) · 74 unmodified lines
823817 int i;
824818 SValue tmp;
825819
820+ vcheck_cmp();
826821 tmp = vtop[-n + 1];
827822 for(i=-n+1;i!=0;i++)
828823 vtop[i] = vtop[i+1];
@@ -837,6 +832,7 @@ ST_FUNC void vrote(SValue *e, int n) · 8 unmodified lines
837832 int i;
838833 SValue tmp;
839834
835+ vcheck_cmp();
840836 tmp = *e;
841837 for(i = 0;i < n - 1; i++)
842838 e[-i] = e[-i - 1];
@@ -851,6 +847,75 @@ ST_FUNC void vrott(int n) · 8 unmodified lines
851847 vrote(vtop, n);
852848 }
853849
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+/* ------------------------------------------------------------------------- */
854919 /* push a symbol value of TYPE */
855920 static inline void vpushsym(CType *type, Sym *sym)
856921 {
@@ -1591,6 +1656,8 @@ ST_FUNC int gv(int rc) · 734 unmodified lines
15911656 /* restore wanted type */
15921657 vtop->type.t = t1;
15931658 } else {
1659+ if (vtop->r == VT_CMP)
1660+ vset_VT_JMP();
15941661 /* one register type load */
15951662 load(r, vtop);
15961663 }
@@ -1608,13 +1675,10 @@ ST_FUNC int gv(int rc) · 11 unmodified lines
16081675 /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */
16091676 ST_FUNC void gv2(int rc1, int rc2)
16101677 {
1611− int v;
1612−
16131678 /* generate more generic register first. But VT_JMP or VT_CMP
16141679 values must be generated first in all cases to avoid possible
16151680 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) {
16181682 vswap();
16191683 gv(rc1);
16201684 vswap();
@@ -1749,26 +1813,6 @@ static void gv_dup(void) · 128 unmodified lines
17491813 }
17501814 }
17511815
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−
17721816 #if PTR_SIZE == 4
17731817 /* generate CPU independent (unsigned) long long operations */
17741818 static void gen_opl(int op)
@@ -1974,8 +2018,8 @@ static void gen_opl(int op) · 199 unmodified lines
19742018 a = gvtst(1, 0);
19752019 if (op != TOK_EQ) {
19762020 /* generate non equal test */
1977− vpushi(TOK_NE);
1978− vtop->r = VT_CMP;
2021+ vpushi(0);
2022+ vset_VT_CMP(TOK_NE);
19792023 b = gvtst(0, 0);
19802024 }
19812025 }
@@ -1990,9 +2034,12 @@ static void gen_opl(int op) · 8 unmodified lines
19902034 else if (op1 == TOK_GE)
19912035 op1 = TOK_UGE;
19922036 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);
19962043 break;
19972044 }
19982045 }
@@ -5001,11 +5048,12 @@ ST_FUNC void unary(void) · 3002 unmodified lines
50015048 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
50025049 gen_cast_s(VT_BOOL);
50035050 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);
50095057 }
50105058 break;
50115059 case '~':
@@ -5035,7 +5083,9 @@ ST_FUNC void unary(void) · 23 unmodified lines
50355083 next();
50365084 in_sizeof++;
50375085 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 */
50395089 size = type_size(&type, &align);
50405090 if (s && s->a.aligned)
50415091 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
56535703 gsym(t);
56545704 nocode_wanted -= f;
56555705 } else {
5656− vseti(VT_JMP + i, gvtst(i, t));
5706+ gvtst_set(i, t);
56575707 }
56585708 break;
56595709 }
@@ -5696,6 +5746,16 @@ static int condition_3way(void) · 36 unmodified lines
56965746 return c;
56975747 }
56985748
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+
56995759 static void expr_cond(void)
57005760 {
57015761 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
57415801 if (!g)
57425802 gexpr();
57435803
5804+ if (c < 0 && vtop->r == VT_CMP) {
5805+ t1 = gvtst(0, 0);
5806+ vpushi(0);
5807+ gvtst_set(0, t1);
5808+ }
5809+
57445810 if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
57455811 mk_pointer(&vtop->type);
57465812 type1 = vtop->type;
@@ -5761,6 +5827,22 @@ static void expr_cond(void) · 14 unmodified lines
57615827 skip(':');
57625828 expr_cond();
57635829
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+ }
57645846
57655847 if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
57665848 mk_pointer(&vtop->type);
@@ -6059,12 +6141,16 @@ static int case_cmp(const void *pa, const void *pb) · 292 unmodified lines
60596141 return a < b ? -1 : a > b;
60606142 }
60616143
6144+static void gtst_addr(int t, int a)
6145+{
6146+ gsym_addr(gvtst(0, t), a);
6147+}
6148+
60626149 static void gcase(struct case_t **base, int len, int *bsym)
60636150 {
60646151 struct case_t *p;
60656152 int e;
60666153 int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
6067− gv(RC_INT);
60686154 while (len > 4) {
60696155 /* binary search */
60706156 p = base[len/2];
@@ -6074,7 +6160,7 @@ static void gcase(struct case_t **base, int len, int *bsym) · 3 unmodified lines
60746160 else
60756161 vpushi(p->v2);
60766162 gen_op(TOK_LE);
6077− e = gtst(1, 0);
6163+ e = gvtst(1, 0);
60786164 vdup();
60796165 if (ll)
60806166 vpushll(p->v1);
@@ -6084,10 +6170,6 @@ static void gcase(struct case_t **base, int len, int *bsym) · 3 unmodified lines
60846170 gtst_addr(0, p->sym); /* v1 <= x <= v2 */
60856171 /* x < v1 */
60866172 gcase(base, len/2, bsym);
6087− if (cur_switch->def_sym)
6088− gjmp_addr(cur_switch->def_sym);
6089− else
6090− *bsym = gjmp(*bsym);
60916173 /* x > v2 */
60926174 gsym(e);
60936175 e = len/2 + 1;
@@ -6106,7 +6188,7 @@ static void gcase(struct case_t **base, int len, int *bsym) · 12 unmodified lines
61066188 gtst_addr(0, p->sym);
61076189 } else {
61086190 gen_op(TOK_LE);
6109− e = gtst(1, 0);
6191+ e = gvtst(1, 0);
61106192 vdup();
61116193 if (ll)
61126194 vpushll(p->v1);
@@ -6117,6 +6199,7 @@ static void gcase(struct case_t **base, int len, int *bsym) · 4 unmodified lines
61176199 gsym(e);
61186200 }
61196201 }
6202+ *bsym = gjmp(*bsym);
61206203 }
61216204
61226205 /* 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
63676450 gexpr();
63686451 skip(')');
63696452 switchval = *vtop--;
6370− a = 0;
6371− b = gjmp(0); /* jump to first case */
6453+
63726454 sw.p = NULL; sw.n = 0; sw.def_sym = 0;
63736455 saved = cur_switch;
63746456 cur_switch = &sw;
6457+ a = 0;
6458+ b = gjmp(0); /* jump to first case */
63756459 block(&a, current_cleanups, csym, ccl, 0);
63766460 a = gjmp(a); /* add implicit break */
63776461 /* case lookup */
63786462 gsym(b);
6463+
63796464 qsort(sw.p, sw.n, sizeof(void*), case_cmp);
63806465 for (b = 1; b < sw.n; b++)
63816466 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
63856470 if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
63866471 switchval.type.t &= ~VT_UNSIGNED;
63876472 vpushv(&switchval);
6388− gcase(sw.p, sw.n, &a);
6473+ gv(RC_INT);
6474+ d = 0, gcase(sw.p, sw.n, &d);
63896475 vpop();
63906476 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);
63946480 /* break label */
63956481 gsym(a);
6482+ dynarray_reset(&sw.p, &sw.n);
6483+ cur_switch = saved;
63966484
63976485 } else if (t == TOK_CASE) {
63986486 struct case_t *cr = tcc_malloc(sizeof(struct case_t));
tests/tcctest.c+3−1
@@ -3777,6 +3777,7 @@ void math_cmp_test(void) · 3776 unmodified lines
37773777 double one = 1.0;
37783778 double two = 2.0;
37793779 int comp = 0;
3780+ int v;
37803781 #define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part)
37813782
37823783 /* 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
37983799 if ((a iop b) || comp) \
37993800 ; \
38003801 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);
38023804
38033805 /* Equality tests. */
38043806 FCMP(nan, nan, ==, !=, 0);
x86_64-gen.c+31−69
@@ -471,22 +471,22 @@ void load(int r, SValue *sv) · 470 unmodified lines
471471 orex(1,0,r,0x8d); /* lea xxx(%ebp), r */
472472 gen_modrm(r, VT_LOCAL, sv->sym, fc);
473473 } 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 */
479474 if (fc & 0x100)
480475 {
476+ v = vtop->cmp_r;
477+ fc &= ~0x100;
481478 /* This was a float compare. If the parity bit is
482479 set the result was unordered, meaning false for everything
483480 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+ }
487485 orex(0,r,0, 0x0f); /* setxx %br */
488486 o(fc);
489487 o(0xc0 + REG_VALUE(r));
488+ orex(0,r,0, 0x0f);
489+ o(0xc0b6 + REG_VALUE(r) * 0x900); /* movzbl %al, %eax */
490490 } else if (v == VT_JMP || v == VT_JMPI) {
491491 t = v & 1;
492492 orex(0,r,0,0);
@@ -1666,42 +1666,23 @@ void gjmp_addr(int a) · 1173 unmodified lines
16661666 }
16671667 }
16681668
1669−ST_FUNC void gtst_addr(int inv, int a)
1669+ST_FUNC int gjmp_append(int n, int t)
16701670 {
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;
16921679 }
1680+ return t;
16931681 }
16941682
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)
16971684 {
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)
17051686 {
17061687 /* This was a float compare. If the parity flag is set
17071688 the result was unordered. For anything except != this
@@ -1710,9 +1691,10 @@ ST_FUNC int gtst(int inv, int t) · 2 unmodified lines
17101691 Take care about inverting the test. We need to jump
17111692 to our target if the result was unordered and test wasn't NE,
17121693 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 */
17161698 else
17171699 {
17181700 g(0x0f);
@@ -1720,25 +1702,8 @@ ST_FUNC int gtst(int inv, int t) · 1 unmodified line
17201702 }
17211703 }
17221704 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;
17421707 }
17431708
17441709 /* generate an integer binary operation */
@@ -1779,10 +1744,8 @@ void gen_opi(int op) · 34 unmodified lines
17791744 o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8);
17801745 }
17811746 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);
17861749 break;
17871750 case '-':
17881751 case TOK_SUBC1: /* sub with carry generation */
@@ -1937,8 +1900,7 @@ void gen_opf(int op) · 148 unmodified lines
19371900 op = TOK_EQ;
19381901 }
19391902 vtop--;
1940− vtop->r = VT_CMP;
1941− vtop->c.i = op;
1903+ vset_VT_CMP(op);
19421904 } else {
19431905 /* no memory reference possible for long double operations */
19441906 load(TREG_ST0, vtop);
@@ -2016,8 +1978,8 @@ void gen_opf(int op) · 71 unmodified lines
20161978 }
20171979
20181980 vtop--;
2019− vtop->r = VT_CMP;
2020− vtop->c.i = op | 0x100;
1981+ vset_VT_CMP(op | 0x100);
1982+ vtop->cmp_r = op;
20211983 } else {
20221984 assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE);
20231985 switch(op) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t