commit 1988c974137f3042d9c38000fda3e00779fecab3 Author: Jiang Date: Fri Aug 1 16:27:58 2014 +0800 fix bitfields see: http://lists.nongnu.org/archive/html/tinycc-devel/2014-07/msg00023.html diff --git a/tcc.h b/tcc.h index c93cedf..a8cabb6 100644 --- a/tcc.h +++ b/tcc.h @@ -1192,6 +1192,17 @@ ST_DATA int func_var; /* true if current function is variadic */ ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; +/* gen_ctrl */ +enum { + CTRL_NONE, + CTRL_CALL, + CTRL_FOCE, + CTRL_ARGS, + CTRL_RETS, + CTRL_INIT, + CTRL_USED, +}; +ST_DATA int gen_ctrl; ST_INLN int is_float(int t); ST_FUNC int ieee_finite(double d); diff --git a/tccgen.c b/tccgen.c index 1a89d4a..73b759f 100644 --- a/tccgen.c +++ b/tccgen.c @@ -70,6 +70,7 @@ ST_DATA int func_var; /* true if current function is variadic (used by return in ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; +ST_DATA int gen_ctrl; ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; @@ -1909,8 +1910,9 @@ static void force_charshort_cast(int t) /* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ static void gen_cast(CType *type) { - int sbt, dbt, sf, df, c, p; + int sbt, dbt, dt, sf, df, c, p, bb; + bb = type->t & VT_BITFIELD; /* special delayed cast for char/short */ /* XXX: in some cases (multiple cascaded casts), it may still be incorrect */ @@ -1925,9 +1927,10 @@ static void gen_cast(CType *type) } dbt = type->t & (VT_BTYPE | VT_UNSIGNED); + dt = dbt & VT_BTYPE; sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); - if (sbt != dbt) { + if (sbt != dbt || bb) { sf = is_float(sbt); df = is_float(dbt); c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; @@ -1959,6 +1962,8 @@ static void gen_cast(CType *type) vtop->c.d = (double)vtop->c.ld; } else if (sf && dbt == (VT_LLONG|VT_UNSIGNED)) { vtop->c.ull = (unsigned long long)vtop->c.ld; + if(bb) + goto to_min; } else if (sf && dbt == VT_BOOL) { vtop->c.i = (vtop->c.ld != 0); } else { @@ -1975,24 +1980,53 @@ static void gen_cast(CType *type) else if (sbt != VT_LLONG) vtop->c.ll = vtop->c.i; - if (dbt == (VT_LLONG|VT_UNSIGNED)) + if (dbt == (VT_LLONG|VT_UNSIGNED)){ vtop->c.ull = vtop->c.ll; - else if (dbt == VT_BOOL) + if(bb) + goto to_min; + }else if (dbt == VT_BOOL) vtop->c.i = (vtop->c.ll != 0); #ifdef TCC_TARGET_X86_64 else if (dbt == VT_PTR) ; #endif else if (dbt != VT_LLONG) { - int s = 0; - if ((dbt & VT_BTYPE) == VT_BYTE) - s = 24; - else if ((dbt & VT_BTYPE) == VT_SHORT) - s = 16; - if(dbt & VT_UNSIGNED) - vtop->c.ui = ((unsigned int)vtop->c.ll << s) >> s; - else - vtop->c.i = ((int)vtop->c.ll << s) >> s; + unsigned long long ull; + long long ll; + int s, warr; +to_min: + warr = 0; + if(bb){ + s = 64 - ((type->t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); + type->t = type->t & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); + }else if (dt == VT_BYTE){ + s = 56; + }else if (dt == VT_SHORT){ + s = 48; + }else{ + s = 32; + } + + ull = (vtop->c.ull << s) >> s; + ll = (vtop->c.ll << s) >> s; + if(ull != vtop->c.ull && ll != vtop->c.ll){ + warr = 1; + } + if(warr){ + if(dt == VT_ENUM) + dbt |= VT_UNSIGNED; + if(gen_ctrl != CTRL_FOCE){ + if(dt == VT_ENUM) + tcc_warning("large integer implicitly truncated to unsigned type"); + else + tcc_warning("overflow in implicit constant conversion"); + } + } + if(dbt & VT_UNSIGNED){ + vtop->c.ull = ull; + }else{ + vtop->c.ll = ll; + } } } } else if (p && dbt == VT_BOOL) { @@ -2024,67 +2058,78 @@ static void gen_cast(CType *type) gen_cast(type); } } + } else { + #ifndef TCC_TARGET_X86_64 - } else if ((dbt & VT_BTYPE) == VT_LLONG) { - if ((sbt & VT_BTYPE) != VT_LLONG) { - /* scalar to long long */ - /* machine independent conversion */ - gv(RC_INT); - /* generate high word */ - if (sbt == (VT_INT | VT_UNSIGNED)) { - vpushi(0); + if ((dbt & VT_BTYPE) == VT_LLONG) { + if ((sbt & VT_BTYPE) != VT_LLONG) { + /* scalar to long long */ + /* machine independent conversion */ gv(RC_INT); - } else { - if (sbt == VT_PTR) { - /* cast from pointer to int before we apply - shift operation, which pointers don't support*/ - gen_cast(&int_type); + /* generate high word */ + if (sbt == (VT_INT | VT_UNSIGNED)) { + vpushi(0); + gv(RC_INT); + } else { + if (sbt == VT_PTR) { + /* cast from pointer to int before we apply + shift operation, which pointers don't support*/ + gen_cast(&int_type); + } + gv_dup(); + vpushi(31); + gen_op(TOK_SAR); } - gv_dup(); - vpushi(31); - gen_op(TOK_SAR); + /* patch second register */ + vtop[-1].r2 = vtop->r; + vpop(); } - /* patch second register */ - vtop[-1].r2 = vtop->r; - vpop(); } #else - } else if ((dbt & VT_BTYPE) == VT_LLONG || - (dbt & VT_BTYPE) == VT_PTR || - (dbt & VT_BTYPE) == VT_FUNC) { - if ((sbt & VT_BTYPE) != VT_LLONG && - (sbt & VT_BTYPE) != VT_PTR && - (sbt & VT_BTYPE) != VT_FUNC) { - /* need to convert from 32bit to 64bit */ - int r = gv(RC_INT); - if (sbt != (VT_INT | VT_UNSIGNED)) { - /* x86_64 specific: movslq */ - o(0x6348); - o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); + if((dbt & VT_BTYPE) == VT_LLONG || (dbt & VT_BTYPE) == VT_PTR || + (dbt & VT_BTYPE) == VT_FUNC) { + if ((sbt & VT_BTYPE) != VT_LLONG && (sbt & VT_BTYPE) != VT_PTR && + (sbt & VT_BTYPE) != VT_FUNC) { + /* need to convert from 32bit to 64bit */ + int r = gv(RC_INT); + if (sbt != (VT_INT | VT_UNSIGNED)) { + /* x86_64 specific: movslq */ + o(0x6348); + o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); + } } } #endif - } else if (dbt == VT_BOOL) { - /* scalar to bool */ - vpushi(0); - gen_op(TOK_NE); - } else if ((dbt & VT_BTYPE) == VT_BYTE || - (dbt & VT_BTYPE) == VT_SHORT) { - if (sbt == VT_PTR) { - vtop->type.t = VT_INT; - tcc_warning("nonportable conversion from pointer to char/short"); + else if (dbt == VT_BOOL) { + /* scalar to bool */ + vpushi(0); + gen_op(TOK_NE); + } else if ((dbt & VT_BTYPE) == VT_BYTE || (dbt & VT_BTYPE) == VT_SHORT) { + if (sbt == VT_PTR) { + vtop->type.t = VT_INT; + tcc_warning("nonportable conversion from pointer to char/short"); + } + force_charshort_cast(dbt); + } else if ((dbt & VT_BTYPE) == VT_INT) { + /* scalar to int */ + if (sbt == VT_LLONG) { + /* from long long: just take low order word */ + lexpand(); + vpop(); + } + /* if lvalue and single word type, nothing to do because + the lvalue already contains the real type size (see + VT_LVAL_xxx constants) */ + } + if(bb){ + int bit_size = (type->t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; + type->t = type->t & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); + if(dt == VT_LLONG) + vpushll((1ULL << bit_size) - 1ULL); + else + vpushi((1 << bit_size) - 1); + gen_op('&'); } - force_charshort_cast(dbt); - } else if ((dbt & VT_BTYPE) == VT_INT) { - /* scalar to int */ - if (sbt == VT_LLONG) { - /* from long long: just take low order word */ - lexpand(); - vpop(); - } - /* if lvalue and single word type, nothing to do because - the lvalue already contains the real type size (see - VT_LVAL_xxx constants) */ } } } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) { @@ -2463,24 +2508,36 @@ static void gen_assign_cast(CType *dt) /* store vtop in lvalue pushed on stack */ ST_FUNC void vstore(void) { - int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; + int sbt, dbt, ft, cc, r, t, size, align, bit_size, bit_pos, rc, delayed_cast, ret; ft = vtop[-1].type.t; sbt = vtop->type.t & VT_BTYPE; dbt = ft & VT_BTYPE; + ret = delayed_cast = 0; + cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || - (sbt == VT_INT && dbt == VT_SHORT)) - && !(vtop->type.t & VT_BITFIELD)) { + (sbt == VT_INT && dbt == VT_SHORT)) && !(vtop->type.t & VT_BITFIELD) && !cc) { /* optimize char/short casts */ delayed_cast = VT_MUSTCAST; vtop->type.t = ft & (VT_TYPE & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT))); /* XXX: factorize */ if (ft & VT_CONSTANT) tcc_warning("assignment of read-only location"); + }else if(ft & VT_BITFIELD){ + ret = (vtop > (vstack + 1) || gen_ctrl == CTRL_INIT); + if(dbt == VT_BOOL) + vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); + gen_assign_cast(&vtop[-1].type); + if(ret){ + if((vtop->r & (VT_VALMASK|VT_LVAL|VT_SYM)) < VT_CONST){ + gv_dup(); + }else{ + vpushv(&vtop[0]); + } + vrott(3); + } } else { - delayed_cast = 0; - if (!(ft & VT_BITFIELD)) - gen_assign_cast(&vtop[-1].type); + gen_assign_cast(&vtop[-1].type); } if (sbt == VT_STRUCT) { @@ -2522,37 +2579,18 @@ ST_FUNC void vstore(void) /* bitfield store handling */ bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; + /* remove bit field info to avoid loops */ vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); - /* duplicate source into other register */ - gv_dup(); - vswap(); - vrott(3); - - if((ft & VT_BTYPE) == VT_BOOL) { - gen_cast(&vtop[-1].type); - vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); - } + vpushi(bit_pos); + gen_op(TOK_SHL); /* duplicate destination */ - vdup(); - vtop[-1] = vtop[-2]; + vpushv(&vtop[-1]); - /* mask and shift source */ - if((ft & VT_BTYPE) != VT_BOOL) { - if((ft & VT_BTYPE) == VT_LLONG) { - vpushll((1ULL << bit_size) - 1ULL); - } else { - vpushi((1 << bit_size) - 1); - } - gen_op('&'); - } - vpushi(bit_pos); - gen_op(TOK_SHL); /* load destination, mask and or with source */ - vswap(); - if((ft & VT_BTYPE) == VT_LLONG) { + if(dbt == VT_LLONG) { vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos)); } else { vpushi(~(((1 << bit_size) - 1) << bit_pos)); @@ -2563,8 +2601,8 @@ ST_FUNC void vstore(void) vstore(); /* pop off shifted source from "duplicate source..." above */ - vpop(); - + if(ret) + vtop--; } else { #ifdef CONFIG_TCC_BCHECK /* bound check case */ @@ -3605,7 +3643,7 @@ static void vpush_tokc(int t) ST_FUNC void unary(void) { - int n, t, align, size, r, sizeof_caller; + int n, t, align, size, r, sizeof_caller, save_ctrl; CType type; Sym *s; AttributeDef ad; @@ -3714,7 +3752,10 @@ ST_FUNC void unary(void) return; } unary(); + save_ctrl = gen_ctrl; + gen_ctrl = CTRL_FOCE; gen_cast(&type); + gen_ctrl = save_ctrl; } } else if (tok == '{') { /* save all registers */ @@ -5127,7 +5168,7 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, static void init_putv(CType *type, Section *sec, unsigned long c, int v, int expr_type) { - int saved_global_expr, bt, bit_pos, bit_size; + int saved_global_expr, bt, bit_pos, bit_size, save_ctrl; void *ptr; unsigned long long bit_mask; CType dtype; @@ -5147,7 +5188,10 @@ static void init_putv(CType *type, Section *sec, unsigned long c, tcc_error("initializer element is not constant"); break; case EXPR_ANY: + save_ctrl = gen_ctrl; + gen_ctrl = CTRL_INIT; expr_eq(); + gen_ctrl = save_ctrl; break; } diff --git a/tests/tests2/03_struct.c b/tests/tests2/03_struct.c index c5d48c5..e06d20d 100644 --- a/tests/tests2/03_struct.c +++ b/tests/tests2/03_struct.c @@ -27,5 +27,36 @@ int main() printf("%d\n", jones[1].boris); printf("%d\n", jones[1].natasha); + struct sbf1 { + int f1 : 3; + int : 2; + int f2 : 1; + int : 0; + int f3 : 5; + int f4 : 7; + unsigned int f5 : 7; + } st1; + st1.f1 = st1.f2 = st1.f3 = st1.f4 = st1.f5 = 3; + printf("%d %d %d %d %d\n", + st1.f1, st1.f2, st1.f3, st1.f4, st1.f5); + + struct { unsigned a:9, b:7, c:5; } s1; + s1.a = s1.b = s1.c = 3; + printf("%d / %d / %d\n", s1.a, s1.b, s1.c); + + struct { + unsigned a:9, b:5, c:7; + } s2, *ps = &s2; + int n = 250; + + int ii = ps->a = ps->b = ps->c = n + 4; + printf("%d / %d / %d\n", ps->a, ps->b, ps->c); + printf("%d\n", ii); + + ps->a = n + 4; + ps->b = n + 4; + ps->c = n + 4; + printf("%d / %d / %d\n", ps->a, ps->b, ps->c); + return 0; } diff --git a/tests/tests2/03_struct.expect b/tests/tests2/03_struct.expect index ecbf589..6b90186 100644 --- a/tests/tests2/03_struct.expect +++ b/tests/tests2/03_struct.expect @@ -1,6 +1,12 @@ +03_struct.c:39: warning: overflow in implicit constant conversion 12 34 12 34 56 78 +-1 -1 3 3 3 +3 / 3 / 3 +30 / 30 / 126 +30 +254 / 30 / 126