History

Fix 64bit enums and switch cases

See testcases. We now support 64bit case constants. At the same time also 64bit enum constants on L64 platforms (otherwise the Sym struct isn't large enough for now). The testcase also checks for various cases where sign/zero extension was confused.

Michael Matz committed 10 years ago

Commit 22f5fcc1 parent 3e77bfb3 files · +196 −41Browse files

Unified · Split

3 files
  1. tcc.h +3 −3
  2. tccgen.c +76 −38
  3. tests/tcctest.c +117 −0
tcc.h+3−3
@@ -1103,11 +1103,11 @@ ST_FUNC void cstr_reset(CString *cstr); · 1102 unmodified lines
1103ST_INLN void sym_free(Sym *sym);1103ST_INLN void sym_free(Sym *sym);
1104ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c);1104ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c);
1105ST_FUNC Sym *sym_find2(Sym *s, int v);1105ST_FUNC Sym *sym_find2(Sym *s, int v);
1106ST_FUNC Sym *sym_push(int v, CType *type, int r, int c);1106ST_FUNC Sym *sym_push(int v, CType *type, int r, long c);
1107ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);1107ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);
1108ST_INLN Sym *struct_find(int v);1108ST_INLN Sym *struct_find(int v);
1109ST_INLN Sym *sym_find(int v);1109ST_INLN Sym *sym_find(int v);
1110ST_FUNC Sym *global_identifier_push(int v, int t, int c);1110ST_FUNC Sym *global_identifier_push(int v, int t, long c);
1111 1111
1112ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);1112ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
1113ST_FUNC int tcc_open(TCCState *s1, const char *filename);1113ST_FUNC int tcc_open(TCCState *s1, const char *filename);
@@ -1271,7 +1271,7 @@ ST_FUNC void test_lvalue(void); · 157 unmodified lines
1271ST_FUNC void swap(int *p, int *q);1271ST_FUNC void swap(int *p, int *q);
1272ST_FUNC void vpushi(int v);1272ST_FUNC void vpushi(int v);
1273ST_FUNC Sym *external_global_sym(int v, CType *type, int r);1273ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
1274ST_FUNC void vset(CType *type, int r, int v);1274ST_FUNC void vset(CType *type, int r, long v);
1275ST_FUNC void vswap(void);1275ST_FUNC void vswap(void);
1276ST_FUNC void vpush_global_sym(CType *type, int v);1276ST_FUNC void vpush_global_sym(CType *type, int v);
1277ST_FUNC void vrote(SValue *e, int n);1277ST_FUNC void vrote(SValue *e, int n);
tccgen.c+76−38
@@ -62,7 +62,8 @@ ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; · 61 unmodified lines
62 62
63ST_DATA struct switch_t {63ST_DATA struct switch_t {
64 struct case_t {64 struct case_t {
65 int v1, v2, sym;65 int64_t v1, v2;
66 int sym;
66 } **p; int n; /* list of case ranges */67 } **p; int n; /* list of case ranges */
67 int def_sym; /* default symbol */68 int def_sym; /* default symbol */
68} *cur_switch; /* current switch */69} *cur_switch; /* current switch */
@@ -86,6 +87,7 @@ static void vla_sp_restore(void); · 17 unmodified lines
86static void vla_sp_restore_root(void);87static void vla_sp_restore_root(void);
87static int is_compatible_parameter_types(CType *type1, CType *type2);88static int is_compatible_parameter_types(CType *type1, CType *type2);
88static void expr_type(CType *type);89static void expr_type(CType *type);
90static inline int64_t expr_const64(void);
89ST_FUNC void vpush64(int ty, unsigned long long v);91ST_FUNC void vpush64(int ty, unsigned long long v);
90ST_FUNC void vpush(CType *type);92ST_FUNC void vpush(CType *type);
91ST_FUNC int gvtst(int inv, int t);93ST_FUNC int gvtst(int inv, int t);
@@ -434,7 +436,7 @@ ST_INLN Sym *sym_find(int v) · 342 unmodified lines
434}436}
435 437
436/* push a given symbol on the symbol stack */438/* push a given symbol on the symbol stack */
437ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)439ST_FUNC Sym *sym_push(int v, CType *type, int r, long c)
438{440{
439 Sym *s, **ps;441 Sym *s, **ps;
440 TokenSym *ts;442 TokenSym *ts;
@@ -466,7 +468,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) · 25 unmodified lines
466}468}
467 469
468/* push a global identifier */470/* push a global identifier */
469ST_FUNC Sym *global_identifier_push(int v, int t, int c)471ST_FUNC Sym *global_identifier_push(int v, int t, long c)
470{472{
471 Sym *s, **ps;473 Sym *s, **ps;
472 s = sym_push2(&global_stack, v, t, c);474 s = sym_push2(&global_stack, v, t, c);
@@ -698,7 +700,7 @@ ST_FUNC void vpush_global_sym(CType *type, int v) · 225 unmodified lines
698 vpushsym(type, external_global_sym(v, type, 0));700 vpushsym(type, external_global_sym(v, type, 0));
699}701}
700 702
701ST_FUNC void vset(CType *type, int r, int v)703ST_FUNC void vset(CType *type, int r, long v)
702{704{
703 CValue cval;705 CValue cval;
704 706
@@ -1716,6 +1718,9 @@ static void gen_opic(int op) · 1011 unmodified lines
1716 default:1718 default:
1717 goto general_case;1719 goto general_case;
1718 }1720 }
1721 if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR))
1722 l1 = ((uint32_t)l1 |
1723 (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000)));
1719 v1->c.i = l1;1724 v1->c.i = l1;
1720 vtop--;1725 vtop--;
1721 } else {1726 } else {
@@ -3248,7 +3253,8 @@ static Sym * find_field (CType *type, int v) · 1526 unmodified lines
3248/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */3253/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
3249static void struct_decl(CType *type, AttributeDef *ad, int u)3254static void struct_decl(CType *type, AttributeDef *ad, int u)
3250{3255{
3251 int a, v, size, align, maxalign, c, offset, flexible, extra_bytes;3256 int a, v, size, align, maxalign, offset, flexible, extra_bytes;
3257 long c;
3252 int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;3258 int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;
3253 Sym *s, *ss, *ass, **ps;3259 Sym *s, *ss, *ass, **ps;
3254 AttributeDef ad1;3260 AttributeDef ad1;
@@ -3293,7 +3299,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 38 unmodified lines
3293 /* non empty enums are not allowed */3299 /* non empty enums are not allowed */
3294 if (a == TOK_ENUM) {3300 if (a == TOK_ENUM) {
3295 int seen_neg = 0;3301 int seen_neg = 0;
3302 int seen_wide = 0;
3296 for(;;) {3303 for(;;) {
3304 CType *t = &int_type;
3297 v = tok;3305 v = tok;
3298 if (v < TOK_UIDENT)3306 if (v < TOK_UIDENT)
3299 expect("identifier");3307 expect("identifier");
@@ -3304,12 +3312,23 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 4 unmodified lines
3304 next();3312 next();
3305 if (tok == '=') {3313 if (tok == '=') {
3306 next();3314 next();
3315#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
3316 c = expr_const64();
3317#else
3318 /* We really want to support long long enums
3319 on i386 as well, but the Sym structure only
3320 holds a 'long' for associated constants,
3321 and enlarging it would bump its size (no
3322 available padding). So punt for now. */
3307 c = expr_const();3323 c = expr_const();
3324#endif
3308 }3325 }
3309 if (c < 0)3326 if (c < 0)
3310 seen_neg = 1;3327 seen_neg = 1;
3328 if (c != (int)c && (unsigned long)c != (unsigned int)c)
3329 seen_wide = 1, t = &size_type;
3311 /* enum symbols have static storage */3330 /* enum symbols have static storage */
3312 ss = sym_push(v, &int_type, VT_CONST, c);3331 ss = sym_push(v, t, VT_CONST, c);
3313 ss->type.t |= VT_STATIC;3332 ss->type.t |= VT_STATIC;
3314 if (tok != ',')3333 if (tok != ',')
3315 break;3334 break;
@@ -3321,7 +3340,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 5 unmodified lines
3321 }3340 }
3322 if (!seen_neg)3341 if (!seen_neg)
3323 s->a.unsigned_enum = 1;3342 s->a.unsigned_enum = 1;
3324 s->c = type_size(&int_type, &align);3343 s->c = type_size(seen_wide ? &size_type : &int_type, &align);
3325 skip('}');3344 skip('}');
3326 } else {3345 } else {
3327 maxalign = 1;3346 maxalign = 1;
@@ -4355,10 +4374,11 @@ ST_FUNC void unary(void) · 1027 unmodified lines
4355 break;4374 break;
4356 case TOK_builtin_choose_expr:4375 case TOK_builtin_choose_expr:
4357 {4376 {
4358 int saved_nocode_wanted, c;4377 int saved_nocode_wanted;
4378 int64_t c;
4359 next();4379 next();
4360 skip('(');4380 skip('(');
4361 c = expr_const();4381 c = expr_const64();
4362 skip(',');4382 skip(',');
4363 if (!c) {4383 if (!c) {
4364 saved_nocode_wanted = nocode_wanted;4384 saved_nocode_wanted = nocode_wanted;
@@ -5272,9 +5292,9 @@ static void expr_const1(void) · 907 unmodified lines
5272}5292}
5273 5293
5274/* parse an integer constant and return its value. */5294/* parse an integer constant and return its value. */
5275ST_FUNC int expr_const(void)5295static inline int64_t expr_const64(void)
5276{5296{
5277 int c;5297 int64_t c;
5278 expr_const1();5298 expr_const1();
5279 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)5299 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
5280 expect("constant expression");5300 expect("constant expression");
@@ -5283,6 +5303,18 @@ ST_FUNC int expr_const(void) · 2 unmodified lines
5283 return c;5303 return c;
5284}5304}
5285 5305
5306/* parse an integer constant and return its value.
5307 Complain if it doesn't fit 32bit (signed or unsigned). */
5308ST_FUNC int expr_const(void)
5309{
5310 int c;
5311 int64_t wc = expr_const64();
5312 c = wc;
5313 if (c != wc && (unsigned)c != wc)
5314 tcc_error("constant exceeds 32 bit");
5315 return c;
5316}
5317
5286/* return the label token if current token is a label, otherwise5318/* return the label token if current token is a label, otherwise
5287 return zero */5319 return zero */
5288static int is_label(void)5320static int is_label(void)
@@ -5325,34 +5357,36 @@ static void label_or_decl(int l) · 36 unmodified lines
5325 5357
5326static int case_cmp(const void *pa, const void *pb)5358static int case_cmp(const void *pa, const void *pb)
5327{5359{
5328 int a = (*(struct case_t**) pa)->v1;5360 int64_t a = (*(struct case_t**) pa)->v1;
5329 int b = (*(struct case_t**) pb)->v1;5361 int64_t b = (*(struct case_t**) pb)->v1;
5330 return a < b ? -1 : a > b;5362 return a < b ? -1 : a > b;
5331}5363}
5332 5364
5333static int gcase(struct case_t **base, int len, int case_reg, int *bsym)5365static void gcase(struct case_t **base, int len, int *bsym)
5334{5366{
5335 struct case_t *p;5367 struct case_t *p;
5336 int e;5368 int e;
5369 int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
5370 gv(RC_INT);
5337 while (len > 4) {5371 while (len > 4) {
5338 /* binary search */5372 /* binary search */
5339 p = base[len/2];5373 p = base[len/2];
5340 vseti(case_reg, 0);
5341 vdup();5374 vdup();
5342 vpushi(p->v2);5375 if (ll)
5376 vpushll(p->v2);
5377 else
5378 vpushi(p->v2);
5343 gen_op(TOK_LE);5379 gen_op(TOK_LE);
5344 e = gtst(1, 0);5380 e = gtst(1, 0);
5345 case_reg = gv(RC_INT);
5346 vpop();
5347 vseti(case_reg, 0);
5348 vdup();5381 vdup();
5349 vpushi(p->v1);5382 if (ll)
5383 vpushll(p->v1);
5384 else
5385 vpushi(p->v1);
5350 gen_op(TOK_GE);5386 gen_op(TOK_GE);
5351 gtst_addr(0, p->sym); /* v1 <= x <= v2 */5387 gtst_addr(0, p->sym); /* v1 <= x <= v2 */
5352 case_reg = gv(RC_INT);
5353 vpop();
5354 /* x < v1 */5388 /* x < v1 */
5355 case_reg = gcase(base, len/2, case_reg, bsym);5389 gcase(base, len/2, bsym);
5356 if (cur_switch->def_sym)5390 if (cur_switch->def_sym)
5357 gjmp_addr(cur_switch->def_sym);5391 gjmp_addr(cur_switch->def_sym);
5358 else5392 else
@@ -5365,28 +5399,27 @@ static int gcase(struct case_t **base, int len, int case_reg, int *bsym) · 6 unmodified lines
5365 /* linear scan */5399 /* linear scan */
5366 while (len--) {5400 while (len--) {
5367 p = *base++;5401 p = *base++;
5368 vseti(case_reg, 0);
5369 vdup();5402 vdup();
5370 vpushi(p->v2);5403 if (ll)
5404 vpushll(p->v2);
5405 else
5406 vpushi(p->v2);
5371 if (p->v1 == p->v2) {5407 if (p->v1 == p->v2) {
5372 gen_op(TOK_EQ);5408 gen_op(TOK_EQ);
5373 gtst_addr(0, p->sym);5409 gtst_addr(0, p->sym);
5374 } else {5410 } else {
5375 gen_op(TOK_LE);5411 gen_op(TOK_LE);
5376 e = gtst(1, 0);5412 e = gtst(1, 0);
5377 case_reg = gv(RC_INT);
5378 vpop();
5379 vseti(case_reg, 0);
5380 vdup();5413 vdup();
5381 vpushi(p->v1);5414 if (ll)
5415 vpushll(p->v1);
5416 else
5417 vpushi(p->v1);
5382 gen_op(TOK_GE);5418 gen_op(TOK_GE);
5383 gtst_addr(0, p->sym);5419 gtst_addr(0, p->sym);
5384 gsym(e);5420 gsym(e);
5385 }5421 }
5386 case_reg = gv(RC_INT);
5387 vpop();
5388 }5422 }
5389 return case_reg;
5390}5423}
5391 5424
5392static void block(int *bsym, int *csym, int is_expr)5425static void block(int *bsym, int *csym, int is_expr)
@@ -5675,13 +5708,12 @@ static void block(int *bsym, int *csym, int is_expr) · 282 unmodified lines
5675 if (tok == TOK_SWITCH) {5708 if (tok == TOK_SWITCH) {
5676 struct switch_t *saved, sw;5709 struct switch_t *saved, sw;
5677 int saved_nocode_wanted = nocode_wanted;5710 int saved_nocode_wanted = nocode_wanted;
5711 SValue switchval;
5678 next();5712 next();
5679 skip('(');5713 skip('(');
5680 gexpr();5714 gexpr();
5681 /* XXX: other types than integer */
5682 c = gv(RC_INT);
5683 vpop();
5684 skip(')');5715 skip(')');
5716 switchval = *vtop--;
5685 a = 0;5717 a = 0;
5686 b = gjmp(0); /* jump to first case */5718 b = gjmp(0); /* jump to first case */
5687 sw.p = NULL; sw.n = 0; sw.def_sym = 0;5719 sw.p = NULL; sw.n = 0; sw.def_sym = 0;
@@ -5697,7 +5729,13 @@ static void block(int *bsym, int *csym, int is_expr) · 9 unmodified lines
5697 for (b = 1; b < sw.n; b++)5729 for (b = 1; b < sw.n; b++)
5698 if (sw.p[b - 1]->v2 >= sw.p[b]->v1)5730 if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
5699 tcc_error("duplicate case value");5731 tcc_error("duplicate case value");
5700 gcase(sw.p, sw.n, c, &a);5732 /* Our switch table sorting is signed, so the compared
5733 value needs to be as well when it's 64bit. */
5734 if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
5735 switchval.type.t &= ~VT_UNSIGNED;
5736 vpushv(&switchval);
5737 gcase(sw.p, sw.n, &a);
5738 vpop();
5701 if (sw.def_sym)5739 if (sw.def_sym)
5702 gjmp_addr(sw.def_sym);5740 gjmp_addr(sw.def_sym);
5703 }5741 }
@@ -5712,10 +5750,10 @@ static void block(int *bsym, int *csym, int is_expr) · 8 unmodified lines
5712 expect("switch");5750 expect("switch");
5713 nocode_wanted &= ~2;5751 nocode_wanted &= ~2;
5714 next();5752 next();
5715 cr->v1 = cr->v2 = expr_const();5753 cr->v1 = cr->v2 = expr_const64();
5716 if (gnu_ext && tok == TOK_DOTS) {5754 if (gnu_ext && tok == TOK_DOTS) {
5717 next();5755 next();
5718 cr->v2 = expr_const();5756 cr->v2 = expr_const64();
5719 if (cr->v2 < cr->v1)5757 if (cr->v2 < cr->v1)
5720 tcc_warning("empty case range");5758 tcc_warning("empty case range");
5721 }5759 }
tests/tcctest.c+117−0
@@ -606,6 +606,24 @@ enum test { · 605 unmodified lines
606struct S_enum {606struct S_enum {
607 enum {E6 = 42, E7, E8} e:8;607 enum {E6 = 42, E7, E8} e:8;
608};608};
609
610enum ELong {
611 /* This is either 0 on L32 machines, or a large number
612 on L64 machines. We should be able to store this. */
613 EL_large = (unsigned long)0xf000 << 32,
614};
615
616enum { BIASU = -1U<<31 };
617enum { BIASS = -1 << 31 };
618
619static int getint(int i)
620{
621 if (i)
622 return 0;
623 else
624 return (int)(-1U << 31);
625}
626
609void enum_test()627void enum_test()
610{628{
611 enum test b1;629 enum test b1;
@@ -617,6 +635,16 @@ void enum_test() · 5 unmodified lines
617 E0, E1, E2, E3, E4, E5);635 E0, E1, E2, E3, E4, E5);
618 b1 = 1;636 b1 = 1;
619 printf("b1=%d\n", b1);637 printf("b1=%d\n", b1);
638 printf("enum large: %ld\n", EL_large);
639
640 if (getint(0) == BIASU)
641 printf("enum unsigned: ok\n");
642 else
643 printf("enum unsigned: wrong\n");
644 if (getint(0) == BIASS)
645 printf("enum unsigned: ok\n");
646 else
647 printf("enum unsigned: wrong\n");
620}648}
621 649
622typedef int *my_ptr;650typedef int *my_ptr;
@@ -1727,10 +1755,45 @@ void init_test(void) · 1104 unmodified lines
1727 printf("linit18= %d %d\n", linit18[0], linit18[1]);1755 printf("linit18= %d %d\n", linit18[0], linit18[1]);
1728}1756}
1729 1757
1758void switch_uc(unsigned char uc)
1759{
1760 switch (uc) {
1761 case 0xfb ... 0xfe:
1762 printf("ucsw:1\n");
1763 break;
1764 case 0xff:
1765 printf("ucsw:2\n");
1766 break;
1767 case 0 ... 5:
1768 printf("ucsw:3\n");
1769 break;
1770 default:
1771 printf("ucsw: broken!\n");
1772 }
1773}
1774
1775void switch_sc(signed char sc)
1776{
1777 switch (sc) {
1778 case -5 ... -2:
1779 printf("scsw:1\n");
1780 break;
1781 case -1:
1782 printf("scsw:2\n");
1783 break;
1784 case 0 ... 5:
1785 printf("scsw:3\n");
1786 break;
1787 default:
1788 printf("scsw: broken!\n");
1789 }
1790}
1730 1791
1731void switch_test()1792void switch_test()
1732{1793{
1733 int i;1794 int i;
1795 unsigned long long ull;
1796 long long ll;
1734 1797
1735 for(i=0;i<15;i++) {1798 for(i=0;i<15;i++) {
1736 switch(i) {1799 switch(i) {
@@ -1753,6 +1816,60 @@ void switch_test() · 16 unmodified lines
1753 }1816 }
1754 }1817 }
1755 printf("\n");1818 printf("\n");
1819
1820 for (i = 1; i <= 5; i++) {
1821 ull = (unsigned long long)i << 61;
1822 switch (ull) {
1823 case 1ULL << 61:
1824 printf("ullsw:1\n");
1825 break;
1826 case 2ULL << 61:
1827 printf("ullsw:2\n");
1828 break;
1829 case 3ULL << 61:
1830 printf("ullsw:3\n");
1831 break;
1832 case 4ULL << 61:
1833 printf("ullsw:4\n");
1834 break;
1835 case 5ULL << 61:
1836 printf("ullsw:5\n");
1837 break;
1838 default:
1839 printf("ullsw: broken!\n");
1840 }
1841 }
1842
1843 for (i = 1; i <= 5; i++) {
1844 ll = (long long)i << 61;
1845 switch (ll) {
1846 case 1LL << 61:
1847 printf("llsw:1\n");
1848 break;
1849 case 2LL << 61:
1850 printf("llsw:2\n");
1851 break;
1852 case 3LL << 61:
1853 printf("llsw:3\n");
1854 break;
1855 case 4LL << 61:
1856 printf("llsw:4\n");
1857 break;
1858 case 5LL << 61:
1859 printf("llsw:5\n");
1860 break;
1861 default:
1862 printf("llsw: broken!\n");
1863 }
1864 }
1865
1866 for (i = -5; i <= 5; i++) {
1867 switch_uc((unsigned char)i);
1868 }
1869
1870 for (i = -5; i <= 5; i++) {
1871 switch_sc ((signed char)i);
1872 }
1756}1873}
1757 1874
1758/* ISOC99 _Bool type */1875/* ISOC99 _Bool type */

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