commit 1c0c88408b56d0e4e36b795b7d92f25f6606988a Author: Jiang Date: Mon Aug 18 20:25:19 2014 +0800 fix bitfields see: http://lists.nongnu.org/archive/html/tinycc-devel/2014-07/msg00023.html Conflicts: tests/tests2/03_struct.c diff --git a/tcc.h b/tcc.h index c93cedf..fb618ec 100644 --- a/tcc.h +++ b/tcc.h @@ -1192,6 +1192,13 @@ 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_FOCE, + CTRL_INIT, +}; +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 d3d1026..e321f96 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; @@ -1017,6 +1018,7 @@ ST_FUNC void lexpand_nr(void) } #endif +#ifndef TCC_TARGET_X86_64 /* build a long long from two ints */ static void lbuild(int t) { @@ -1025,6 +1027,7 @@ static void lbuild(int t) vtop[-1].type.t = t; vpop(); } +#endif /* rotate n first stack elements to the bottom I1 ... In -> I2 ... In I1 [top is right] @@ -1087,7 +1090,8 @@ static void gv_dup(void) int rc, t, r, r1; SValue sv; - t = vtop->type.t; +#ifndef TCC_TARGET_X86_64 + t = VT_INT; if ((t & VT_BTYPE) == VT_LLONG) { lexpand(); gv_dup(); @@ -1097,15 +1101,16 @@ static void gv_dup(void) vrotb(4); /* stack: H L L1 H1 */ lbuild(t); - vrotb(3); - vrotb(3); + vrott(3); vswap(); lbuild(t); vswap(); - } else { + } else +#else + t = vtop->type.t; +#endif + { /* duplicate value */ - rc = RC_INT; - sv.type.t = VT_INT; if (is_float(t)) { rc = RC_FLOAT; #ifdef TCC_TARGET_X86_64 @@ -1113,8 +1118,9 @@ static void gv_dup(void) rc = RC_ST0; } #endif - sv.type.t = t; - } + }else + rc = RC_INT; + sv.type.t = t; r = gv(rc); r1 = get_reg(rc); sv.r = r; @@ -1909,8 +1915,11 @@ 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, bitfield; + CType dtype; + dtype = *type; + bitfield = dtype.t & VT_BITFIELD; /* special delayed cast for char/short */ /* XXX: in some cases (multiple cascaded casts), it may still be incorrect */ @@ -1924,10 +1933,11 @@ static void gen_cast(CType *type) gv(RC_INT); } - dbt = type->t & (VT_BTYPE | VT_UNSIGNED); + dbt = dtype.t & (VT_BTYPE | VT_UNSIGNED); + dt = dbt & VT_BTYPE; sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); - if (sbt != dbt) { + if (sbt != dbt || bitfield) { sf = is_float(sbt); df = is_float(dbt); c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; @@ -1959,6 +1969,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(bitfield) + goto cast_bitfield; } else if (sf && dbt == VT_BOOL) { vtop->c.i = (vtop->c.ld != 0); } else { @@ -1975,24 +1987,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(bitfield) + goto cast_bitfield; + }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; +cast_bitfield: + warr = 0; + if(bitfield){ + s = 64 - ((dtype.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); + dtype.t = dtype.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) { @@ -2018,14 +2059,33 @@ static void gen_cast(CType *type) dbt != VT_LLONG) dbt = VT_INT; gen_cvt_ftoi1(dbt); - if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { + if (dbt == VT_INT && (dtype.t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { /* additional cast for char/short... */ vtop->type.t = dbt; gen_cast(type); } } + } else if (dbt == VT_BOOL) { + /* scalar to bool */ + vpushi(0); + gen_op(TOK_NE); + }else if(bitfield){ + int bits, bit_size = (dtype.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; + + dtype.t = dtype.t & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); + gen_cast(&dtype); + if (dt == VT_LLONG) { + bits = 64 - bit_size; + } else + bits = 32 - bit_size; + vpushi(bits); + gen_op(TOK_SHL); + vpushi(bits); + /* NOTE: transformed to SHR if unsigned */ + gen_op(TOK_SAR); + }else #ifndef TCC_TARGET_X86_64 - } else if ((dbt & VT_BTYPE) == VT_LLONG) { + if ((dbt & VT_BTYPE) == VT_LLONG) { if ((sbt & VT_BTYPE) != VT_LLONG) { /* scalar to long long */ /* machine independent conversion */ @@ -2048,12 +2108,11 @@ static void gen_cast(CType *type) 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 && + 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); @@ -2063,13 +2122,9 @@ static void gen_cast(CType *type) 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) { + 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"); @@ -2081,7 +2136,7 @@ static void gen_cast(CType *type) /* 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) */ @@ -2093,7 +2148,7 @@ static void gen_cast(CType *type) vtop->r = (vtop->r & ~VT_LVAL_TYPE) | (lvalue_type(type->ref->type.t) & VT_LVAL_TYPE); } - vtop->type = *type; + vtop->type = dtype; } /* return type size as known at compile time. Put alignment at 'a' */ @@ -2463,24 +2518,35 @@ 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; - if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || - (sbt == VT_INT && dbt == VT_SHORT)) - && !(vtop->type.t & VT_BITFIELD)) { + ret = delayed_cast = 0; + cc = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; + if (ft & VT_BITFIELD) { + ret = (vtop > (vstack + 1) || gen_ctrl == CTRL_INIT); + gen_cast(&vtop[-1].type); + if(dbt == VT_BOOL) + vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); + if(ret){ + if((vtop->r & (VT_VALMASK|VT_LVAL|VT_SYM)) < VT_CONST){ + gv_dup(); + }else{ + vpushv(&vtop[0]); + } + vrott(3); + } + }else if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || + (sbt == VT_INT && dbt == VT_SHORT)) && !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 { - 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 +2588,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 +2610,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 */ @@ -3610,7 +3657,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; @@ -3719,7 +3766,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 */ @@ -5132,9 +5182,8 @@ 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; switch(expr_type) { @@ -5152,7 +5201,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; } @@ -5173,11 +5225,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, if (!(type->t & VT_BITFIELD)) { bit_pos = 0; bit_size = 32; - bit_mask = -1LL; } else { - bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; - bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; - bit_mask = (1LL << bit_size) - 1; + bit_pos = (dtype.t >> VT_STRUCT_SHIFT) & 0x3f; + bit_size = (dtype.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; } if ((vtop->r & VT_SYM) && (bt == VT_BYTE || @@ -5191,10 +5241,10 @@ static void init_putv(CType *type, Section *sec, unsigned long c, case VT_BOOL: vtop->c.i = (vtop->c.i != 0); case VT_BYTE: - *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; + *(char *)ptr |= vtop->c.i << bit_pos; break; case VT_SHORT: - *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; + *(short *)ptr |= vtop->c.i << bit_pos; break; case VT_DOUBLE: *(double *)ptr = vtop->c.d; @@ -5203,19 +5253,19 @@ static void init_putv(CType *type, Section *sec, unsigned long c, *(long double *)ptr = vtop->c.ld; break; case VT_LLONG: - *(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos; + *(long long *)ptr |= vtop->c.ll << bit_pos; break; case VT_PTR: if (vtop->r & VT_SYM) { greloc(sec, vtop->sym, c, R_DATA_PTR); } - *(addr_t *)ptr |= (vtop->c.ptr_offset & bit_mask) << bit_pos; + *(addr_t *)ptr |= vtop->c.ptr_offset << bit_pos; break; default: if (vtop->r & VT_SYM) { greloc(sec, vtop->sym, c, R_DATA_PTR); } - *(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos; + *(int *)ptr |= vtop->c.i << bit_pos; break; } vtop--; diff --git a/tests/tests2/03_struct.c b/tests/tests2/03_struct.c index 3b99e30..8b3acee 100644 --- a/tests/tests2/03_struct.c +++ b/tests/tests2/03_struct.c @@ -13,12 +13,24 @@ static int eval_rept() return 0; } +struct command_switch { + unsigned int env:1; /* Can come from MAKEFLAGS. */ + unsigned int toenv:1; /* Should be put in MAKEFLAGS. */ + unsigned int no_makefile:1; /* Don't propagate when remaking makefiles. */ +}; +static const struct command_switch switches = {1, 1, 3}; + struct fred { int boris; int natasha; }; +void foo(int a, int b, int c) +{ + printf("%d / %d / %d\n", a, b, c); +} + int main() { struct fred bloggs; @@ -43,5 +55,40 @@ int main() printf("%d\n", jones[1].boris); printf("%d\n", jones[1].natasha); - return 0; + 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); + + printf("%d, %d, %d\n", switches.env, switches.toenv, switches.no_makefile); + + foo(ps->a = n + 4, ps->b = n + 4, ps->c = n + 4); + + return 0; } diff --git a/tests/tests2/03_struct.expect b/tests/tests2/03_struct.expect index ecbf589..e6a0db1 100644 --- a/tests/tests2/03_struct.expect +++ b/tests/tests2/03_struct.expect @@ -1,6 +1,15 @@ +03_struct.c:8: warning: overflow in implicit constant conversion +03_struct.c:51: 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 +1, 1, 1 +254 / 30 / 126