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
11031103 ST_INLN void sym_free(Sym *sym);
11041104 ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c);
11051105 ST_FUNC Sym *sym_find2(Sym *s, int v);
1106−ST_FUNC Sym *sym_push(int v, CType *type, int r, int c);
1106+ST_FUNC Sym *sym_push(int v, CType *type, int r, long c);
11071107 ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);
11081108 ST_INLN Sym *struct_find(int v);
11091109 ST_INLN Sym *sym_find(int v);
1110−ST_FUNC Sym *global_identifier_push(int v, int t, int c);
1110+ST_FUNC Sym *global_identifier_push(int v, int t, long c);
11111111
11121112 ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
11131113 ST_FUNC int tcc_open(TCCState *s1, const char *filename);
@@ -1271,7 +1271,7 @@ ST_FUNC void test_lvalue(void); · 157 unmodified lines
12711271 ST_FUNC void swap(int *p, int *q);
12721272 ST_FUNC void vpushi(int v);
12731273 ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
1274−ST_FUNC void vset(CType *type, int r, int v);
1274+ST_FUNC void vset(CType *type, int r, long v);
12751275 ST_FUNC void vswap(void);
12761276 ST_FUNC void vpush_global_sym(CType *type, int v);
12771277 ST_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
6262
6363 ST_DATA struct switch_t {
6464 struct case_t {
65− int v1, v2, sym;
65+ int64_t v1, v2;
66+ int sym;
6667 } **p; int n; /* list of case ranges */
6768 int def_sym; /* default symbol */
6869 } *cur_switch; /* current switch */
@@ -86,6 +87,7 @@ static void vla_sp_restore(void); · 17 unmodified lines
8687 static void vla_sp_restore_root(void);
8788 static int is_compatible_parameter_types(CType *type1, CType *type2);
8889 static void expr_type(CType *type);
90+static inline int64_t expr_const64(void);
8991 ST_FUNC void vpush64(int ty, unsigned long long v);
9092 ST_FUNC void vpush(CType *type);
9193 ST_FUNC int gvtst(int inv, int t);
@@ -434,7 +436,7 @@ ST_INLN Sym *sym_find(int v) · 342 unmodified lines
434436 }
435437
436438 /* push a given symbol on the symbol stack */
437−ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
439+ST_FUNC Sym *sym_push(int v, CType *type, int r, long c)
438440 {
439441 Sym *s, **ps;
440442 TokenSym *ts;
@@ -466,7 +468,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) · 25 unmodified lines
466468 }
467469
468470 /* push a global identifier */
469−ST_FUNC Sym *global_identifier_push(int v, int t, int c)
471+ST_FUNC Sym *global_identifier_push(int v, int t, long c)
470472 {
471473 Sym *s, **ps;
472474 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
698700 vpushsym(type, external_global_sym(v, type, 0));
699701 }
700702
701−ST_FUNC void vset(CType *type, int r, int v)
703+ST_FUNC void vset(CType *type, int r, long v)
702704 {
703705 CValue cval;
704706
@@ -1716,6 +1718,9 @@ static void gen_opic(int op) · 1011 unmodified lines
17161718 default:
17171719 goto general_case;
17181720 }
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)));
17191724 v1->c.i = l1;
17201725 vtop--;
17211726 } else {
@@ -3248,7 +3253,8 @@ static Sym * find_field (CType *type, int v) · 1526 unmodified lines
32483253 /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
32493254 static void struct_decl(CType *type, AttributeDef *ad, int u)
32503255 {
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;
32523258 int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;
32533259 Sym *s, *ss, *ass, **ps;
32543260 AttributeDef ad1;
@@ -3293,7 +3299,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 38 unmodified lines
32933299 /* non empty enums are not allowed */
32943300 if (a == TOK_ENUM) {
32953301 int seen_neg = 0;
3302+ int seen_wide = 0;
32963303 for(;;) {
3304+ CType *t = &int_type;
32973305 v = tok;
32983306 if (v < TOK_UIDENT)
32993307 expect("identifier");
@@ -3304,12 +3312,23 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 4 unmodified lines
33043312 next();
33053313 if (tok == '=') {
33063314 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. */
33073323 c = expr_const();
3324+#endif
33083325 }
33093326 if (c < 0)
33103327 seen_neg = 1;
3328+ if (c != (int)c && (unsigned long)c != (unsigned int)c)
3329+ seen_wide = 1, t = &size_type;
33113330 /* enum symbols have static storage */
3312− ss = sym_push(v, &int_type, VT_CONST, c);
3331+ ss = sym_push(v, t, VT_CONST, c);
33133332 ss->type.t |= VT_STATIC;
33143333 if (tok != ',')
33153334 break;
@@ -3321,7 +3340,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 5 unmodified lines
33213340 }
33223341 if (!seen_neg)
33233342 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);
33253344 skip('}');
33263345 } else {
33273346 maxalign = 1;
@@ -4355,10 +4374,11 @@ ST_FUNC void unary(void) · 1027 unmodified lines
43554374 break;
43564375 case TOK_builtin_choose_expr:
43574376 {
4358− int saved_nocode_wanted, c;
4377+ int saved_nocode_wanted;
4378+ int64_t c;
43594379 next();
43604380 skip('(');
4361− c = expr_const();
4381+ c = expr_const64();
43624382 skip(',');
43634383 if (!c) {
43644384 saved_nocode_wanted = nocode_wanted;
@@ -5272,9 +5292,9 @@ static void expr_const1(void) · 907 unmodified lines
52725292 }
52735293
52745294 /* parse an integer constant and return its value. */
5275−ST_FUNC int expr_const(void)
5295+static inline int64_t expr_const64(void)
52765296 {
5277− int c;
5297+ int64_t c;
52785298 expr_const1();
52795299 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
52805300 expect("constant expression");
@@ -5283,6 +5303,18 @@ ST_FUNC int expr_const(void) · 2 unmodified lines
52835303 return c;
52845304 }
52855305
5306+/* parse an integer constant and return its value.
5307+ Complain if it doesn't fit 32bit (signed or unsigned). */
5308+ST_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+
52865318 /* return the label token if current token is a label, otherwise
52875319 return zero */
52885320 static int is_label(void)
@@ -5325,34 +5357,36 @@ static void label_or_decl(int l) · 36 unmodified lines
53255357
53265358 static int case_cmp(const void *pa, const void *pb)
53275359 {
5328− int a = (*(struct case_t**) pa)->v1;
5329− int b = (*(struct case_t**) pb)->v1;
5360+ int64_t a = (*(struct case_t**) pa)->v1;
5361+ int64_t b = (*(struct case_t**) pb)->v1;
53305362 return a < b ? -1 : a > b;
53315363 }
53325364
5333−static int gcase(struct case_t **base, int len, int case_reg, int *bsym)
5365+static void gcase(struct case_t **base, int len, int *bsym)
53345366 {
53355367 struct case_t *p;
53365368 int e;
5369+ int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
5370+ gv(RC_INT);
53375371 while (len > 4) {
53385372 /* binary search */
53395373 p = base[len/2];
5340− vseti(case_reg, 0);
53415374 vdup();
5342− vpushi(p->v2);
5375+ if (ll)
5376+ vpushll(p->v2);
5377+ else
5378+ vpushi(p->v2);
53435379 gen_op(TOK_LE);
53445380 e = gtst(1, 0);
5345− case_reg = gv(RC_INT);
5346− vpop();
5347− vseti(case_reg, 0);
53485381 vdup();
5349− vpushi(p->v1);
5382+ if (ll)
5383+ vpushll(p->v1);
5384+ else
5385+ vpushi(p->v1);
53505386 gen_op(TOK_GE);
53515387 gtst_addr(0, p->sym); /* v1 <= x <= v2 */
5352− case_reg = gv(RC_INT);
5353− vpop();
53545388 /* x < v1 */
5355− case_reg = gcase(base, len/2, case_reg, bsym);
5389+ gcase(base, len/2, bsym);
53565390 if (cur_switch->def_sym)
53575391 gjmp_addr(cur_switch->def_sym);
53585392 else
@@ -5365,28 +5399,27 @@ static int gcase(struct case_t **base, int len, int case_reg, int *bsym) · 6 unmodified lines
53655399 /* linear scan */
53665400 while (len--) {
53675401 p = *base++;
5368− vseti(case_reg, 0);
53695402 vdup();
5370− vpushi(p->v2);
5403+ if (ll)
5404+ vpushll(p->v2);
5405+ else
5406+ vpushi(p->v2);
53715407 if (p->v1 == p->v2) {
53725408 gen_op(TOK_EQ);
53735409 gtst_addr(0, p->sym);
53745410 } else {
53755411 gen_op(TOK_LE);
53765412 e = gtst(1, 0);
5377− case_reg = gv(RC_INT);
5378− vpop();
5379− vseti(case_reg, 0);
53805413 vdup();
5381− vpushi(p->v1);
5414+ if (ll)
5415+ vpushll(p->v1);
5416+ else
5417+ vpushi(p->v1);
53825418 gen_op(TOK_GE);
53835419 gtst_addr(0, p->sym);
53845420 gsym(e);
53855421 }
5386− case_reg = gv(RC_INT);
5387− vpop();
53885422 }
5389− return case_reg;
53905423 }
53915424
53925425 static 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
56755708 if (tok == TOK_SWITCH) {
56765709 struct switch_t *saved, sw;
56775710 int saved_nocode_wanted = nocode_wanted;
5711+ SValue switchval;
56785712 next();
56795713 skip('(');
56805714 gexpr();
5681− /* XXX: other types than integer */
5682− c = gv(RC_INT);
5683− vpop();
56845715 skip(')');
5716+ switchval = *vtop--;
56855717 a = 0;
56865718 b = gjmp(0); /* jump to first case */
56875719 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
56975729 for (b = 1; b < sw.n; b++)
56985730 if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
56995731 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();
57015739 if (sw.def_sym)
57025740 gjmp_addr(sw.def_sym);
57035741 }
@@ -5712,10 +5750,10 @@ static void block(int *bsym, int *csym, int is_expr) · 8 unmodified lines
57125750 expect("switch");
57135751 nocode_wanted &= ~2;
57145752 next();
5715− cr->v1 = cr->v2 = expr_const();
5753+ cr->v1 = cr->v2 = expr_const64();
57165754 if (gnu_ext && tok == TOK_DOTS) {
57175755 next();
5718− cr->v2 = expr_const();
5756+ cr->v2 = expr_const64();
57195757 if (cr->v2 < cr->v1)
57205758 tcc_warning("empty case range");
57215759 }
tests/tcctest.c+117−0
@@ -606,6 +606,24 @@ enum test { · 605 unmodified lines
606606 struct S_enum {
607607 enum {E6 = 42, E7, E8} e:8;
608608 };
609+
610+enum 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+
616+enum { BIASU = -1U<<31 };
617+enum { BIASS = -1 << 31 };
618+
619+static int getint(int i)
620+{
621+ if (i)
622+ return 0;
623+ else
624+ return (int)(-1U << 31);
625+}
626+
609627 void enum_test()
610628 {
611629 enum test b1;
@@ -617,6 +635,16 @@ void enum_test() · 5 unmodified lines
617635 E0, E1, E2, E3, E4, E5);
618636 b1 = 1;
619637 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");
620648 }
621649
622650 typedef int *my_ptr;
@@ -1727,10 +1755,45 @@ void init_test(void) · 1104 unmodified lines
17271755 printf("linit18= %d %d\n", linit18[0], linit18[1]);
17281756 }
17291757
1758+void 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+
1775+void 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+}
17301791
17311792 void switch_test()
17321793 {
17331794 int i;
1795+ unsigned long long ull;
1796+ long long ll;
17341797
17351798 for(i=0;i<15;i++) {
17361799 switch(i) {
@@ -1753,6 +1816,60 @@ void switch_test() · 16 unmodified lines
17531816 }
17541817 }
17551818 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+ }
17561873 }
17571874
17581875 /* 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