------- 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