The following fixes th PR71310 fix to do what expand does and thus follow the C++ memory model correctly. It also reportedly fixes PR71510 (probably the effective negative bitoffset thing).
Bootstrapped and tested on x86_64-unknown-linux-gnu, inspected the PR71310 testcase on a ppc64le cross. Installed on trunk. Richard. 2016-06-14 Richard Biener <rguent...@suse.de> PR middle-end/71310 PR bootstrap/71510 * expr.h (get_bit_range): Declare. * expr.c (get_bit_range): Export. * fold-const.c (optimize_bit_field_compare): Use get_bit_range and word_mode again to constrain the bitfield access. Index: gcc/expr.c =================================================================== *** gcc/expr.c (revision 237372) --- gcc/expr.c (working copy) *************** optimize_bitfield_assignment_op (unsigne *** 4795,4801 **** If the access does not need to be restricted, 0 is returned in both *BITSTART and *BITEND. */ ! static void get_bit_range (unsigned HOST_WIDE_INT *bitstart, unsigned HOST_WIDE_INT *bitend, tree exp, --- 4795,4801 ---- If the access does not need to be restricted, 0 is returned in both *BITSTART and *BITEND. */ ! void get_bit_range (unsigned HOST_WIDE_INT *bitstart, unsigned HOST_WIDE_INT *bitend, tree exp, Index: gcc/expr.h =================================================================== *** gcc/expr.h (revision 237372) --- gcc/expr.h (working copy) *************** extern rtx push_block (rtx, int, int); *** 242,247 **** --- 242,251 ---- extern bool emit_push_insn (rtx, machine_mode, tree, rtx, unsigned int, int, rtx, int, rtx, rtx, int, rtx, bool); + /* Extract the accessible bit-range from a COMPONENT_REF. */ + extern void get_bit_range (unsigned HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, + tree, HOST_WIDE_INT *, tree *); + /* Expand an assignment that stores the value of FROM into TO. */ extern void expand_assignment (tree, tree, bool); Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 237372) --- gcc/fold-const.c (working copy) *************** optimize_bit_field_compare (location_t l *** 3904,3927 **** return 0; } ! /* Don't use a larger mode for reading the bit field than we will ! use in other places accessing the bit field. */ ! machine_mode largest_mode = word_mode; if (TREE_CODE (lhs) == COMPONENT_REF) { ! tree field = TREE_OPERAND (lhs, 1); ! tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field); ! if (repr) ! largest_mode = DECL_MODE (repr); } /* See if we can find a mode to refer to this field. We should be able to, but fail if we can't. */ ! nmode = get_best_mode (lbitsize, lbitpos, 0, 0, const_p ? TYPE_ALIGN (TREE_TYPE (linner)) : MIN (TYPE_ALIGN (TREE_TYPE (linner)), TYPE_ALIGN (TREE_TYPE (rinner))), ! largest_mode, false); if (nmode == VOIDmode) return 0; --- 3904,3926 ---- return 0; } ! /* Honor the C++ memory model and mimic what RTL expansion does. */ ! unsigned HOST_WIDE_INT bitstart = 0; ! unsigned HOST_WIDE_INT bitend = 0; if (TREE_CODE (lhs) == COMPONENT_REF) { ! get_bit_range (&bitstart, &bitend, lhs, &lbitpos, &offset); ! if (offset != NULL_TREE) ! return 0; } /* See if we can find a mode to refer to this field. We should be able to, but fail if we can't. */ ! nmode = get_best_mode (lbitsize, lbitpos, bitstart, bitend, const_p ? TYPE_ALIGN (TREE_TYPE (linner)) : MIN (TYPE_ALIGN (TREE_TYPE (linner)), TYPE_ALIGN (TREE_TYPE (rinner))), ! word_mode, false); if (nmode == VOIDmode) return 0;