]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/61762 (failure to optimize memcpy from constant string)
authorRichard Biener <rguenther@suse.de>
Fri, 25 Jul 2014 07:44:57 +0000 (07:44 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 25 Jul 2014 07:44:57 +0000 (07:44 +0000)
2014-07-25  Richard Biener  <rguenther@suse.de>

PR middle-end/61762
PR middle-end/61894
* fold-const.c (native_encode_int): Add and handle offset
parameter to do partial encodings of expr.
(native_encode_fixed): Likewise.
(native_encode_real): Likewise.
(native_encode_complex): Likewise.
(native_encode_vector): Likewise.
(native_encode_string): Likewise.
(native_encode_expr): Likewise.
* fold-const.c (native_encode_expr): Add offset parameter
defaulting to -1.
* gimple-fold.c (fold_string_cst_ctor_reference): Remove.
(fold_ctor_reference): Handle all reads from tcc_constant
ctors.

* gcc.dg/pr61762.c: New testcase.
* gcc.dg/fold-cstring.c: Likewise.
* gcc.dg/fold-cvect.c: Likewise.

From-SVN: r213045

gcc/ChangeLog
gcc/fold-const.c
gcc/fold-const.h
gcc/gimple-fold.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/fold-cstring.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/fold-cvect.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr61762.c [new file with mode: 0644]

index a3715aefab841ed3e53d4db588960d93b521c068..268c40a6a5e14bc26d2f7c7df37867465f516815 100644 (file)
@@ -1,3 +1,21 @@
+2014-07-25  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/61762
+       PR middle-end/61894
+       * fold-const.c (native_encode_int): Add and handle offset
+       parameter to do partial encodings of expr.
+       (native_encode_fixed): Likewise.
+       (native_encode_real): Likewise.
+       (native_encode_complex): Likewise.
+       (native_encode_vector): Likewise.
+       (native_encode_string): Likewise.
+       (native_encode_expr): Likewise.
+       * fold-const.c (native_encode_expr): Add offset parameter
+       defaulting to -1.
+       * gimple-fold.c (fold_string_cst_ctor_reference): Remove.
+       (fold_ctor_reference): Handle all reads from tcc_constant
+       ctors.
+
 2014-07-25  Richard Biener  <rguenther@suse.de>
 
        * tree-inline.c (estimate_move_cost): Mark speed_p argument
index ff9e4048b6c86328bf1c0cbcd9dad3dd1faba9b8..0999625dc281dcd2386409abba58f5b6b127c277 100644 (file)
@@ -7240,15 +7240,18 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
    upon failure.  */
 
 static int
-native_encode_int (const_tree expr, unsigned char *ptr, int len)
+native_encode_int (const_tree expr, unsigned char *ptr, int len, int off)
 {
   tree type = TREE_TYPE (expr);
   int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
   int byte, offset, word, words;
   unsigned char value;
 
-  if (total_bytes > len)
+  if ((off == -1 && total_bytes > len)
+      || off >= total_bytes)
     return 0;
+  if (off == -1)
+    off = 0;
   words = total_bytes / UNITS_PER_WORD;
 
   for (byte = 0; byte < total_bytes; byte++)
@@ -7271,9 +7274,11 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len)
        }
       else
        offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
-      ptr[offset] = value;
+      if (offset >= off
+         && offset - off < len)
+       ptr[offset - off] = value;
     }
-  return total_bytes;
+  return MIN (len, total_bytes - off);
 }
 
 
@@ -7283,7 +7288,7 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
+native_encode_fixed (const_tree expr, unsigned char *ptr, int len, int off)
 {
   tree type = TREE_TYPE (expr);
   enum machine_mode mode = TYPE_MODE (type);
@@ -7303,7 +7308,7 @@ native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
   value = TREE_FIXED_CST (expr);
   i_value = double_int_to_tree (i_type, value.data);
 
-  return native_encode_int (i_value, ptr, len);
+  return native_encode_int (i_value, ptr, len, off);
 }
 
 
@@ -7313,7 +7318,7 @@ native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_real (const_tree expr, unsigned char *ptr, int len)
+native_encode_real (const_tree expr, unsigned char *ptr, int len, int off)
 {
   tree type = TREE_TYPE (expr);
   int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
@@ -7325,8 +7330,11 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len)
      up to 192 bits.  */
   long tmp[6];
 
-  if (total_bytes > len)
+  if ((off == -1 && total_bytes > len)
+      || off >= total_bytes)
     return 0;
+  if (off == -1)
+    off = 0;
   words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD;
 
   real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
@@ -7350,9 +7358,12 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len)
        }
       else
        offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
-      ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)] = value;
+      offset = offset + ((bitpos / BITS_PER_UNIT) & ~3);
+      if (offset >= off
+         && offset - off < len)
+       ptr[offset - off] = value;
     }
-  return total_bytes;
+  return MIN (len, total_bytes - off);
 }
 
 /* Subroutine of native_encode_expr.  Encode the COMPLEX_CST
@@ -7361,18 +7372,22 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_complex (const_tree expr, unsigned char *ptr, int len)
+native_encode_complex (const_tree expr, unsigned char *ptr, int len, int off)
 {
   int rsize, isize;
   tree part;
 
   part = TREE_REALPART (expr);
-  rsize = native_encode_expr (part, ptr, len);
-  if (rsize == 0)
+  rsize = native_encode_expr (part, ptr, len, off);
+  if (off == -1
+      && rsize == 0)
     return 0;
   part = TREE_IMAGPART (expr);
-  isize = native_encode_expr (part, ptr+rsize, len-rsize);
-  if (isize != rsize)
+  if (off != -1)
+    off = MAX (0, off - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (part))));
+  isize = native_encode_expr (part, ptr+rsize, len-rsize, off);
+  if (off == -1
+      && isize != rsize)
     return 0;
   return rsize + isize;
 }
@@ -7384,7 +7399,7 @@ native_encode_complex (const_tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_vector (const_tree expr, unsigned char *ptr, int len)
+native_encode_vector (const_tree expr, unsigned char *ptr, int len, int off)
 {
   unsigned i, count;
   int size, offset;
@@ -7396,10 +7411,21 @@ native_encode_vector (const_tree expr, unsigned char *ptr, int len)
   size = GET_MODE_SIZE (TYPE_MODE (itype));
   for (i = 0; i < count; i++)
     {
+      if (off >= size)
+       {
+         off -= size;
+         continue;
+       }
       elem = VECTOR_CST_ELT (expr, i);
-      if (native_encode_expr (elem, ptr+offset, len-offset) != size)
+      int res = native_encode_expr (elem, ptr+offset, len-offset, off);
+      if ((off == -1 && res != size)
+         || res == 0)
        return 0;
-      offset += size;
+      offset += res;
+      if (offset >= len)
+       return offset;
+      if (off != -1)
+       off = 0;
     }
   return offset;
 }
@@ -7411,7 +7437,7 @@ native_encode_vector (const_tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_string (const_tree expr, unsigned char *ptr, int len)
+native_encode_string (const_tree expr, unsigned char *ptr, int len, int off)
 {
   tree type = TREE_TYPE (expr);
   HOST_WIDE_INT total_bytes;
@@ -7422,47 +7448,56 @@ native_encode_string (const_tree expr, unsigned char *ptr, int len)
       || !tree_fits_shwi_p (TYPE_SIZE_UNIT (type)))
     return 0;
   total_bytes = tree_to_shwi (TYPE_SIZE_UNIT (type));
-  if (total_bytes > len)
+  if ((off == -1 && total_bytes > len)
+      || off >= total_bytes)
     return 0;
-  if (TREE_STRING_LENGTH (expr) < total_bytes)
+  if (off == -1)
+    off = 0;
+  if (TREE_STRING_LENGTH (expr) - off < MIN (total_bytes, len))
     {
-      memcpy (ptr, TREE_STRING_POINTER (expr), TREE_STRING_LENGTH (expr));
-      memset (ptr + TREE_STRING_LENGTH (expr), 0,
-             total_bytes - TREE_STRING_LENGTH (expr));
+      int written = 0;
+      if (off < TREE_STRING_LENGTH (expr))
+       {
+         written = MIN (len, TREE_STRING_LENGTH (expr) - off);
+         memcpy (ptr, TREE_STRING_POINTER (expr) + off, written);
+       }
+      memset (ptr + written, 0,
+             MIN (total_bytes - written, len - written));
     }
   else
-    memcpy (ptr, TREE_STRING_POINTER (expr), total_bytes);
-  return total_bytes;
+    memcpy (ptr, TREE_STRING_POINTER (expr) + off, MIN (total_bytes, len));
+  return MIN (total_bytes - off, len);
 }
 
 
 /* Subroutine of fold_view_convert_expr.  Encode the INTEGER_CST,
    REAL_CST, COMPLEX_CST or VECTOR_CST specified by EXPR into the
-   buffer PTR of length LEN bytes.  Return the number of bytes
-   placed in the buffer, or zero upon failure.  */
+   buffer PTR of length LEN bytes.  If OFF is not -1 then start
+   the encoding at byte offset OFF and encode at most LEN bytes.
+   Return the number of bytes placed in the buffer, or zero upon failure.  */
 
 int
-native_encode_expr (const_tree expr, unsigned char *ptr, int len)
+native_encode_expr (const_tree expr, unsigned char *ptr, int len, int off)
 {
   switch (TREE_CODE (expr))
     {
     case INTEGER_CST:
-      return native_encode_int (expr, ptr, len);
+      return native_encode_int (expr, ptr, len, off);
 
     case REAL_CST:
-      return native_encode_real (expr, ptr, len);
+      return native_encode_real (expr, ptr, len, off);
 
     case FIXED_CST:
-      return native_encode_fixed (expr, ptr, len);
+      return native_encode_fixed (expr, ptr, len, off);
 
     case COMPLEX_CST:
-      return native_encode_complex (expr, ptr, len);
+      return native_encode_complex (expr, ptr, len, off);
 
     case VECTOR_CST:
-      return native_encode_vector (expr, ptr, len);
+      return native_encode_vector (expr, ptr, len, off);
 
     case STRING_CST:
-      return native_encode_string (expr, ptr, len);
+      return native_encode_string (expr, ptr, len, off);
 
     default:
       return 0;
index 3b5fd8476d6219463672f32903d4d4bf4ec9b75e..b440ca11881a0c5cbacb9898c459dcb8c127b127 100644 (file)
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 extern int folding_initializer;
 
 /* Convert between trees and native memory representation.  */
-extern int native_encode_expr (const_tree, unsigned char *, int);
+extern int native_encode_expr (const_tree, unsigned char *, int, int off = -1);
 extern tree native_interpret_expr (tree, const unsigned char *, int);
 
 /* Fold constants as much as possible in an expression.
index 4e8de8235f8ec0437ec086c21e2a5dbb9776717c..747c0aa0b359cc947324069217f731f2672e346f 100644 (file)
@@ -2881,41 +2881,6 @@ get_base_constructor (tree base, HOST_WIDE_INT *bit_offset,
     }
 }
 
-/* CTOR is STRING_CST.  Fold reference of type TYPE and size SIZE
-   to the memory at bit OFFSET.
-
-   We do only simple job of folding byte accesses.  */
-
-static tree
-fold_string_cst_ctor_reference (tree type, tree ctor,
-                               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))
-       return build_int_cst_type (type, (TREE_STRING_POINTER (ctor)
-                                  [offset]));
-      /* Folding
-        const char a[20]="hello";
-        return a[10];
-
-        might lead to offset greater than string length.  In this case we
-        know value is either initialized to 0 or out of bounds.  Return 0
-        in both cases.  */
-      return build_zero_cst (type);
-    }
-  return NULL_TREE;
-}
-
 /* CTOR is CONSTRUCTOR of an array type.  Fold reference of type TYPE and size
    SIZE to the memory at bit OFFSET.  */
 
@@ -3107,8 +3072,19 @@ fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
        STRIP_NOPS (ret);
       return ret;
     }
-  if (TREE_CODE (ctor) == STRING_CST)
-    return fold_string_cst_ctor_reference (type, ctor, offset, size);
+  /* For constants and byte-aligned/sized reads try to go through
+     native_encode/interpret.  */
+  if (CONSTANT_CLASS_P (ctor)
+      && BITS_PER_UNIT == 8
+      && offset % BITS_PER_UNIT == 0
+      && size % BITS_PER_UNIT == 0
+      && size <= MAX_BITSIZE_MODE_ANY_MODE)
+    {
+      unsigned char buf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
+      if (native_encode_expr (ctor, buf, size / BITS_PER_UNIT,
+                             offset / BITS_PER_UNIT) > 0)
+       return native_interpret_expr (type, buf, size / BITS_PER_UNIT);
+    }
   if (TREE_CODE (ctor) == CONSTRUCTOR)
     {
 
index 17daa074a940ef7f36f0e07f528e42436505b9f8..72ba8a7a8a85ae90ed43fc9cc8aa1148a7f84656 100644 (file)
@@ -1,3 +1,11 @@
+2014-07-25  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/61762
+       PR middle-end/61894
+       * gcc.dg/pr61762.c: New testcase.
+       * gcc.dg/fold-cstring.c: Likewise.
+       * gcc.dg/fold-cvect.c: Likewise.
+
 2014-07-24  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
 
        * gcc.target/powerpc/ppc64-abi-warn-3.c: New test.
diff --git a/gcc/testsuite/gcc.dg/fold-cstring.c b/gcc/testsuite/gcc.dg/fold-cstring.c
new file mode 100644 (file)
index 0000000..f92b120
--- /dev/null
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-options "-O" } */
+
+/* The following are testcases for native_interpret_int,
+   native_interpret_complex and native_interpret_vector decoding
+   pieces of a string constant encoded by native_encode_string.  */
+
+extern void abort (void);
+
+/* We should fold all reads from xconstant and eliminate it, removing
+   the reference to blah which cannot be resolved at link time.  */
+extern int blah;
+
+static const struct {
+    int *y;
+    const char x[32] __attribute__((aligned(32)));
+} xconstant = { &blah, "01234567899876543210123456789000" };
+
+typedef int v4si __attribute__((vector_size(16)));
+
+int main()
+{
+  if (sizeof (int) != 4)
+    return 0;
+  if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+    {
+      if (*(int *)&xconstant.x[4] != 0x34353637)
+       abort ();
+      if ((*(v4si *)&xconstant.x[16])[1] != 0x31323334)
+       abort ();
+      if (__imag (*(_Complex int *)&xconstant.x[8]) != 0x37363534)
+       abort ();
+    }
+  else if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+    {
+      if (*(int *)&xconstant.x[4] != 0x37363534)
+       abort ();
+      if ((*(v4si *)&xconstant.x[16])[1] != 0x34333231)
+       abort ();
+      if (__imag (*(_Complex int *)&xconstant.x[8]) != 0x34353637)
+       abort ();
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/fold-cvect.c b/gcc/testsuite/gcc.dg/fold-cvect.c
new file mode 100644 (file)
index 0000000..8687f8d
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+/* { dg-options "-O" } */
+
+extern void abort (void);
+
+/* We should fold all reads from xconstant and eliminate it, removing
+   the reference to blah which cannot be resolved at link time.  */
+extern int blah;
+
+typedef int v4si __attribute__((vector_size(16)));
+
+static const struct {
+    int *y;
+    const v4si x[2] __attribute__((aligned(32)));
+} xconstant = { &blah, { { 0, 1, 2, 3 }, { 2, 3, 4, 5 } } };
+
+int main()
+{
+  if (sizeof (int) != 4)
+    return 0;
+  if (*(int *)&xconstant.x[0][0] != 0)
+    abort ();
+  if (*(int *)&xconstant.x[0][1] != 1)
+    abort ();
+  if (*(int *)&xconstant.x[0][2] != 2)
+    abort ();
+  if (*(int *)&xconstant.x[0][3] != 3)
+    abort ();
+  if (*(int *)&xconstant.x[1][0] != 2)
+    abort ();
+  if (*(int *)&xconstant.x[1][1] != 3)
+    abort ();
+  if (*(int *)&xconstant.x[1][2] != 4)
+    abort ();
+  if (*(int *)&xconstant.x[1][3] != 5)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr61762.c b/gcc/testsuite/gcc.dg/pr61762.c
new file mode 100644 (file)
index 0000000..5abe534
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-release_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.  CCP
+   already performs the simplification but only after release_ssa
+   the unused local static is removed.  */
+
+/* { dg-final { scan-tree-dump-not "Private" "release_ssa" } } */
+/* { dg-final { cleanup-tree-dump "release_ssa" } } */