The following fixes PR69047, update-address-taken can use the same trick as VN and re-write MEM[&d] into SSA when the size of the MEM and the size of d do not match by using a BIT_FIELD_REF.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. The patch contains a workaround for PR77390. Richard. 2016-08-26 Richard Biener <rguent...@suse.de> PR tree-optimization/69047 * tree-ssa.c (maybe_rewrite_mem_ref_base): Handle general bitfield extracts similar to what FRE does. (non_rewritable_mem_ref_base): Likewise. * gcc.dg/pr69047.c: New testcase. Index: gcc/tree-ssa.c =================================================================== --- gcc/tree-ssa.c (revision 239752) +++ gcc/tree-ssa.c (working copy) @@ -1292,7 +1292,9 @@ maybe_rewrite_mem_ref_base (tree *tp, bi && (sym = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0)) && DECL_P (sym) && !TREE_ADDRESSABLE (sym) - && bitmap_bit_p (suitable_for_renaming, DECL_UID (sym))) + && bitmap_bit_p (suitable_for_renaming, DECL_UID (sym)) + && is_gimple_reg_type (TREE_TYPE (*tp)) + && ! VOID_TYPE_P (TREE_TYPE (*tp))) { if (TREE_CODE (TREE_TYPE (sym)) == VECTOR_TYPE && useless_type_conversion_p (TREE_TYPE (*tp), @@ -1314,7 +1316,8 @@ maybe_rewrite_mem_ref_base (tree *tp, bi ? REALPART_EXPR : IMAGPART_EXPR, TREE_TYPE (*tp), sym); } - else if (integer_zerop (TREE_OPERAND (*tp, 1))) + else if (integer_zerop (TREE_OPERAND (*tp, 1)) + && DECL_SIZE (sym) == TYPE_SIZE (TREE_TYPE (*tp))) { if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (sym))) @@ -1323,6 +1326,24 @@ maybe_rewrite_mem_ref_base (tree *tp, bi else *tp = sym; } + else if (DECL_SIZE (sym) + && TREE_CODE (DECL_SIZE (sym)) == INTEGER_CST + && mem_ref_offset (*tp) >= 0 + && wi::leu_p (mem_ref_offset (*tp) + + wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (*tp))), + wi::to_offset (DECL_SIZE_UNIT (sym))) + && (! INTEGRAL_TYPE_P (TREE_TYPE (*tp)) + || (wi::to_offset (TYPE_SIZE (TREE_TYPE (*tp))) + == TYPE_PRECISION (TREE_TYPE (*tp)))) + && wi::umod_trunc (wi::to_offset (TYPE_SIZE (TREE_TYPE (*tp))), + BITS_PER_UNIT) == 0) + { + *tp = build3 (BIT_FIELD_REF, TREE_TYPE (*tp), sym, + TYPE_SIZE (TREE_TYPE (*tp)), + wide_int_to_tree (bitsizetype, + mem_ref_offset (*tp) + << LOG2_BITS_PER_UNIT)); + } } } @@ -1352,6 +1373,11 @@ non_rewritable_mem_ref_base (tree ref) && TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR) { tree decl = TREE_OPERAND (TREE_OPERAND (base, 0), 0); + if (! DECL_P (decl)) + return NULL_TREE; + if (! is_gimple_reg_type (TREE_TYPE (base)) + || VOID_TYPE_P (TREE_TYPE (base))) + return decl; if ((TREE_CODE (TREE_TYPE (decl)) == VECTOR_TYPE || TREE_CODE (TREE_TYPE (decl)) == COMPLEX_TYPE) && useless_type_conversion_p (TREE_TYPE (base), @@ -1362,12 +1388,28 @@ non_rewritable_mem_ref_base (tree ref) && multiple_of_p (sizetype, TREE_OPERAND (base, 1), TYPE_SIZE_UNIT (TREE_TYPE (base)))) return NULL_TREE; - if (DECL_P (decl) - && (!integer_zerop (TREE_OPERAND (base, 1)) - || (DECL_SIZE (decl) - != TYPE_SIZE (TREE_TYPE (base))) - || TREE_THIS_VOLATILE (decl) != TREE_THIS_VOLATILE (base))) - return decl; + /* For same sizes and zero offset we can use a VIEW_CONVERT_EXPR. */ + if (integer_zerop (TREE_OPERAND (base, 1)) + && DECL_SIZE (decl) == TYPE_SIZE (TREE_TYPE (base))) + return NULL_TREE; + /* For integral typed extracts we can use a BIT_FIELD_REF. */ + if (DECL_SIZE (decl) + && TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST + && mem_ref_offset (base) >= 0 + && wi::leu_p (mem_ref_offset (base) + + wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (base))), + wi::to_offset (DECL_SIZE_UNIT (decl))) + /* ??? We can't handle bitfield precision extracts without + either using an alternate type for the BIT_FIELD_REF and + then doing a conversion or possibly adjusting the offset + according to endianess. */ + && (! INTEGRAL_TYPE_P (TREE_TYPE (base)) + || (wi::to_offset (TYPE_SIZE (TREE_TYPE (base))) + == TYPE_PRECISION (TREE_TYPE (base)))) + && wi::umod_trunc (wi::to_offset (TYPE_SIZE (TREE_TYPE (base))), + BITS_PER_UNIT) == 0) + return NULL_TREE; + return decl; } return NULL_TREE; Index: gcc/testsuite/gcc.dg/pr69047.c =================================================================== --- gcc/testsuite/gcc.dg/pr69047.c (revision 0) +++ gcc/testsuite/gcc.dg/pr69047.c (working copy) @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-cddce1" } */ + +__UINT8_TYPE__ +f(__UINT16_TYPE__ b) +{ + __UINT8_TYPE__ a; +#if __BYTE_ORDER == __LITTLE_ENDIAN + __builtin_memcpy(&a, &b, sizeof a); +#elif __BYTE_ORDER == __BIG_ENDIAN + __builtin_memcpy(&a, (char *)&b + sizeof a, sizeof a); +#else + a = b; +#endif + return a; +} + +/* { dg-final { scan-tree-dump "_\[0-9\]+ = \\(\[^)\]+\\) b" "cddce1" } } */