The following makes sure we fold the reads from string constants created from folding memcpy (&foo, &string_cst[0], ...) to eventually create similar code as if that memcpy folding wasn't done (move-by-pieces).
Bootstrapped and tested on x86_64-unknown-linux-gnu. Comments? (yeah, those native_encode_expr improvement would be really nice, eventually for a slightly different interface, native_encode_expr_part) Thanks, Richard. 2014-07-10 Richard Biener <rguent...@suse.de> PR middle-end/61762 * gimple-fold.c (fold_string_cst_ctor_reference): Handle all integral-typed reads. * gcc.dg/pr61762.c: New testcase. Index: gcc/gimple-fold.c =================================================================== *** gcc/gimple-fold.c (revision 212356) --- gcc/gimple-fold.c (working copy) *************** fold_string_cst_ctor_reference (tree typ *** 2891,2904 **** unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size) { if (INTEGRAL_TYPE_P (type) && (TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == MODE_INT) && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1 ! && size == BITS_PER_UNIT ! && !(offset % BITS_PER_UNIT)) { offset /= BITS_PER_UNIT; if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor)) --- 2891,2905 ---- unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size) { + if (offset % BITS_PER_UNIT != 0) + return NULL_TREE; if (INTEGRAL_TYPE_P (type) && (TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == MODE_INT) && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1 ! && size == BITS_PER_UNIT) { offset /= BITS_PER_UNIT; if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor)) *************** fold_string_cst_ctor_reference (tree typ *** 2913,2918 **** --- 2914,2932 ---- in both cases. */ return build_zero_cst (type); } + else if (size % BITS_PER_UNIT == 0 + /* ??? Until native_encode_expr understands to only encode + a part of a (possibly very large) constant limit this + to sth larger than MAX_BITSIZE_MODE_ANY_MODE. After that + restriction is removed we can remove the case above. */ + && offset + size < 128 * BITS_PER_UNIT + && BITS_PER_UNIT == 8) + { + unsigned char buf[128]; + if (native_encode_expr (ctor, buf, sizeof (buf)) > 0) + return native_interpret_expr (type, &buf[offset / BITS_PER_UNIT], + size / BITS_PER_UNIT); + } return NULL_TREE; } Index: gcc/testsuite/gcc.dg/pr61762.c =================================================================== *** gcc/testsuite/gcc.dg/pr61762.c (revision 0) --- gcc/testsuite/gcc.dg/pr61762.c (working copy) *************** *** 0 **** --- 1,19 ---- + /* { dg-do compile } */ + /* { dg-options "-O -fdump-tree-ssa" } */ + + unsigned int f() + { + static const char string[] = "Private"; + + unsigned int priv; + __builtin_memcpy(&priv, &string[0], sizeof(priv)); + return priv; + } + + /* We should have removed the static string and simplified the + memcpy to a store from an integer constant. Gimplification + already performs the simplification but only after into-SSA + the unused local static is removed. */ + + /* { dg-final { scan-tree-dump-not "Private" "ssa" } } */ + /* { dg-final { cleanup-tree-dump "ssa" } } */