------- Comment #24 from rguenth at gcc dot gnu dot org 2008-01-15 13:23 ------- So the issue is that for
void foo(unsigned int) (i) { <unnamed-unsigned:24> i.0; <bb 2>: i.0 = (<unnamed-unsigned:24>) i; sv.f2 = i.0; if ((unsigned int) i.0 != 0) we neither emit code for the narrowing nor for the widening, but only for the bitfield store: ;; i.0 = (<unnamed-unsigned:24>) i (insn 6 5 0 t.ii:16 (set (reg:SI 58 [ i.0 ]) (reg/v:SI 59 [ i ])) -1 (nil)) ;; sv.f2 = i.0 ... proper code ;; if ((unsigned int) i.0 != 0) (insn 14 13 15 t.ii:18 (set (reg:CCZ 17 flags) (compare:CCZ (reg:SI 58 [ i.0 ]) (const_int 0 [0x0]))) -1 (nil)) (jump_insn 15 14 0 t.ii:18 (set (pc) (if_then_else (eq (reg:CCZ 17 flags) (const_int 0 [0x0])) (label_ref 0) (pc))) -1 (expr_list:REG_BR_PROB (const_int 9900 [0x26ac]) (nil))) see how we simply re-use the incoming register for the comparison. Neither did we truncate that, nor do we zero-extend before the comparison. The C frontend produces the same IL but due to the activated langhook we instead expand to ;; i.0 = (<unnamed-unsigned:24>) i (insn 6 5 0 t.i:12 (parallel [ (set (reg:SI 58 [ i.0 ]) (and:SI (reg/v:SI 59 [ i ]) (const_int 16777215 [0xffffff]))) (clobber (reg:CC 17 flags)) ]) -1 (nil)) ;; sv.f2 = i.0 ... same code as for C++ ;; if ((unsigned int) i.0 != 0) (insn 14 13 15 t.i:14 (set (reg:CCZ 17 flags) (compare:CCZ (reg:SI 58 [ i.0 ]) (const_int 0 [0x0]))) -1 (nil)) (jump_insn 15 14 0 t.i:14 (set (pc) (if_then_else (eq (reg:CCZ 17 flags) (const_int 0 [0x0])) (label_ref 0) (pc))) -1 (expr_list:REG_BR_PROB (const_int 9900 [0x26ac]) (nil))) note we also do not emit code for the widening here. The same is true for the signed case. We can enable this particular behavior for all frontends with Index: expr.c =================================================================== --- expr.c (revision 131542) +++ expr.c (working copy) @@ -7157,7 +7157,11 @@ expand_expr_real_1 (tree exp, rtx target mode = TYPE_MODE (type); unsignedp = TYPE_UNSIGNED (type); } - if (lang_hooks.reduce_bit_field_operations + if ((lang_hooks.reduce_bit_field_operations + /* Always reduce conversion results to the target precision. */ + || code == NON_LVALUE_EXPR + || code == NOP_EXPR + || code == CONVERT_EXPR) && TREE_CODE (type) == INTEGER_TYPE && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type)) { but that breaks libjava again. It also does _not_ fix the original testcase, as that would require reducing also the increment expression. This can be fixed by properly lowering increment expressions as with Index: cp/typeck.c =================================================================== *** cp/typeck.c (revision 131542) --- cp/typeck.c (working copy) *************** build_unary_op (enum tree_code code, tre *** 4340,4345 **** --- 4347,4375 ---- } val = boolean_increment (code, arg); } + /* If the type is a bitfield, lower the expression to an + assignment with a properly promoted bitfield rvalue increment. + + [5.3.2/1] If x is not of type bool, the expression ++x is + equivalent to x+=1. + + thus integer promotions are supposed to happen, and in the + case of bitfields it is important for semantics. */ + else if (INTEGRAL_TYPE_P (argtype) + && (TYPE_PRECISION (argtype) + != GET_MODE_BITSIZE (TYPE_MODE (argtype)))) + { + tree rarg = arg; + if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) + rarg = save_expr (arg); + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + val = build_binary_op (PLUS_EXPR, rarg, inc, 1); + else + val = build_binary_op (MINUS_EXPR, rarg, inc, 1); + val = build_modify_expr (arg, NOP_EXPR, val); + if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) + val = build_compound_expr (val, rarg); + } else val = build2 (code, TREE_TYPE (arg), arg, inc); but this adjustment alone doesn't fix the original testcase either, because we still do the comparison in the bitfield type. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33887