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" } } */

Reply via email to