This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Bug in optimize_bitfield_assignment_op()?
- From: "Bingfeng Mei" <bmei at broadcom dot com>
- To: "gcc at gcc dot gnu dot org" <gcc at gcc dot gnu dot org>
- Date: Thu, 18 Dec 2008 03:40:25 -0800
- Subject: Bug in optimize_bitfield_assignment_op()?
Hello,
My GCC porting for our own VLIW processor tracks mainline weekly. Test 991118-1.c has failed since two weeks ago. Following is a simplified version of 99118-1.c. After some investigation, I found the following statement is expanded to RTL wrongly.
;; tmp2.field = (<unnamed-signed:52>) (<unnamed-signed:52>) ((long long int) tmp2.field ^ 0x8765412345678);
(insn 9 8 10 /projects/firepath/tools/work/bmei/gcc-head/src/gcc/testsuite/gcc.c-torture/execute/991118-1.c:23 (set (reg/f:SI 88)
(symbol_ref:SI ("tmp2") [flags 0x2] <var_decl 0xf7fb8170 tmp2>)) -1 (nil))
(insn 10 9 11 /projects/firepath/tools/work/bmei/gcc-head/src/gcc/testsuite/gcc.c-torture/execute/991118-1.c:23 (set (reg:DI 89)
(mem/s/j/c:DI (reg/f:SI 88) [0+0 S8 A64])) -1 (nil))
(insn 11 10 12 /projects/firepath/tools/work/bmei/gcc-head/src/gcc/testsuite/gcc.c-torture/execute/991118-1.c:23 (set:DI (reg:DI 90)
(const_int 284280 [0x45678])) -1 (nil)) <---- wrong constant
(insn 12 11 13 /projects/firepath/tools/work/bmei/gcc-head/src/gcc/testsuite/gcc.c-torture/execute/991118-1.c:23 (set (reg:DI 91)
(xor:DI (reg:DI 89)
(reg:DI 90))) -1 (nil))
(insn 13 12 0 /projects/firepath/tools/work/bmei/gcc-head/src/gcc/testsuite/gcc.c-torture/execute/991118-1.c:23 (set (mem/s/j/c:DI (reg/f:SI 88) [0+0 S8 A64])
(reg:DI 91)) -1 (nil))
Insn 11 only preserves the lower 20-bit of the 52-bit long constant. Further investigation shows the problem arises in
optimize_bitfield_assignment_op function (expr.c).
...
case BIT_XOR_EXPR:
if (TREE_CODE (op1) != INTEGER_CST)
break;
value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), EXPAND_NORMAL);
value = convert_modes (GET_MODE (str_rtx),
TYPE_MODE (TREE_TYPE (op1)), value,
TYPE_UNSIGNED (TREE_TYPE (op1)));
/* We may be accessing data outside the field, which means
we can alias adjacent data. */
if (MEM_P (str_rtx))
{
str_rtx = shallow_copy_rtx (str_rtx);
set_mem_alias_set (str_rtx, 0);
set_mem_expr (str_rtx, 0);
}
binop = TREE_CODE (src) == BIT_IOR_EXPR ? ior_optab : xor_optab;
if (bitpos + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx)))
{
rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize) <------------ Suspected bug
- 1);
value = expand_and (GET_MODE (str_rtx), value, mask,
NULL_RTX);
}
value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
build_int_cst (NULL_TREE, bitpos),
NULL_RTX, 1);
result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
value, str_rtx, 1, OPTAB_WIDEN);
Here the bitpos = 0, bitsize = 52. HOST_WIDE_INT for our processor is 32, though 64-bit long long type is supported. The marked statement produces a mask of 0xfffff, thus causes the upper 32-bit removed later. Is this a potential bug, or did I miss something?
I also tried the older version (> 2 weeks ago). This function is not called at all, so can produce correct code.
Cheers,
Bingfeng
Broadcom UK