The following fixes PR61762 and 61894 by making folding from
const aggregates use native_encode/interpret when reaching
a tcc_constant initializer.  To make this work efficiently
the patch introduces the ability to encode only a part of
a tree expression, namely from [off, off + len] when off is
not -1 (in which case old semantics apply).

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Richard.

2014-07-24  Richard Biener  <rguent...@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.

Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c.orig       2014-07-16 09:48:06.089217352 +0200
--- gcc/fold-const.c    2014-07-24 12:54:11.483860342 +0200
*************** fold_plusminus_mult_expr (location_t loc
*** 7240,7254 ****
     upon failure.  */
  
  static int
! native_encode_int (const_tree expr, unsigned char *ptr, int len)
  {
    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)
      return 0;
    words = total_bytes / UNITS_PER_WORD;
  
    for (byte = 0; byte < total_bytes; byte++)
--- 7240,7257 ----
     upon failure.  */
  
  static int
! 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 ((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++)
*************** native_encode_int (const_tree expr, unsi
*** 7271,7279 ****
        }
        else
        offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
!       ptr[offset] = value;
      }
!   return total_bytes;
  }
  
  
--- 7274,7284 ----
        }
        else
        offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
!       if (offset >= off
!         && offset - off < len)
!       ptr[offset - off] = value;
      }
!   return MIN (len, total_bytes - off);
  }
  
  
*************** native_encode_int (const_tree expr, unsi
*** 7283,7289 ****
     upon failure.  */
  
  static int
! native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
  {
    tree type = TREE_TYPE (expr);
    enum machine_mode mode = TYPE_MODE (type);
--- 7288,7294 ----
     upon failure.  */
  
  static int
! 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);
*************** native_encode_fixed (const_tree expr, un
*** 7303,7309 ****
    value = TREE_FIXED_CST (expr);
    i_value = double_int_to_tree (i_type, value.data);
  
!   return native_encode_int (i_value, ptr, len);
  }
  
  
--- 7308,7314 ----
    value = TREE_FIXED_CST (expr);
    i_value = double_int_to_tree (i_type, value.data);
  
!   return native_encode_int (i_value, ptr, len, off);
  }
  
  
*************** native_encode_fixed (const_tree expr, un
*** 7313,7319 ****
     upon failure.  */
  
  static int
! native_encode_real (const_tree expr, unsigned char *ptr, int len)
  {
    tree type = TREE_TYPE (expr);
    int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
--- 7318,7324 ----
     upon failure.  */
  
  static int
! 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));
*************** native_encode_real (const_tree expr, uns
*** 7325,7332 ****
       up to 192 bits.  */
    long tmp[6];
  
!   if (total_bytes > len)
      return 0;
    words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD;
  
    real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
--- 7330,7340 ----
       up to 192 bits.  */
    long tmp[6];
  
!   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));
*************** native_encode_real (const_tree expr, uns
*** 7350,7358 ****
        }
        else
        offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
!       ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)] = value;
      }
!   return total_bytes;
  }
  
  /* Subroutine of native_encode_expr.  Encode the COMPLEX_CST
--- 7358,7369 ----
        }
        else
        offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
!       offset = offset + ((bitpos / BITS_PER_UNIT) & ~3);
!       if (offset >= off
!         && offset - off < len)
!       ptr[offset - off] = value;
      }
!   return MIN (len, total_bytes - off);
  }
  
  /* Subroutine of native_encode_expr.  Encode the COMPLEX_CST
*************** native_encode_real (const_tree expr, uns
*** 7361,7378 ****
     upon failure.  */
  
  static int
! native_encode_complex (const_tree expr, unsigned char *ptr, int len)
  {
    int rsize, isize;
    tree part;
  
    part = TREE_REALPART (expr);
!   rsize = native_encode_expr (part, ptr, len);
!   if (rsize == 0)
      return 0;
    part = TREE_IMAGPART (expr);
!   isize = native_encode_expr (part, ptr+rsize, len-rsize);
!   if (isize != rsize)
      return 0;
    return rsize + isize;
  }
--- 7372,7393 ----
     upon failure.  */
  
  static int
! 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, off);
!   if (off == -1
!       && rsize == 0)
      return 0;
    part = TREE_IMAGPART (expr);
!   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;
  }
*************** native_encode_complex (const_tree expr,
*** 7384,7390 ****
     upon failure.  */
  
  static int
! native_encode_vector (const_tree expr, unsigned char *ptr, int len)
  {
    unsigned i, count;
    int size, offset;
--- 7399,7405 ----
     upon failure.  */
  
  static int
! native_encode_vector (const_tree expr, unsigned char *ptr, int len, int off)
  {
    unsigned i, count;
    int size, offset;
*************** native_encode_vector (const_tree expr, u
*** 7396,7405 ****
    size = GET_MODE_SIZE (TYPE_MODE (itype));
    for (i = 0; i < count; i++)
      {
        elem = VECTOR_CST_ELT (expr, i);
!       if (native_encode_expr (elem, ptr+offset, len-offset) != size)
        return 0;
!       offset += size;
      }
    return offset;
  }
--- 7411,7431 ----
    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);
!       int res = native_encode_expr (elem, ptr+offset, len-offset, off);
!       if ((off == -1 && res != size)
!         || res == 0)
        return 0;
!       offset += res;
!       if (offset >= len)
!       return offset;
!       if (off != -1)
!       off = 0;
      }
    return offset;
  }
*************** native_encode_vector (const_tree expr, u
*** 7411,7417 ****
     upon failure.  */
  
  static int
! native_encode_string (const_tree expr, unsigned char *ptr, int len)
  {
    tree type = TREE_TYPE (expr);
    HOST_WIDE_INT total_bytes;
--- 7437,7443 ----
     upon failure.  */
  
  static int
! native_encode_string (const_tree expr, unsigned char *ptr, int len, int off)
  {
    tree type = TREE_TYPE (expr);
    HOST_WIDE_INT total_bytes;
*************** native_encode_string (const_tree expr, u
*** 7422,7468 ****
        || !tree_fits_shwi_p (TYPE_SIZE_UNIT (type)))
      return 0;
    total_bytes = tree_to_shwi (TYPE_SIZE_UNIT (type));
!   if (total_bytes > len)
      return 0;
!   if (TREE_STRING_LENGTH (expr) < total_bytes)
      {
!       memcpy (ptr, TREE_STRING_POINTER (expr), TREE_STRING_LENGTH (expr));
!       memset (ptr + TREE_STRING_LENGTH (expr), 0,
!             total_bytes - TREE_STRING_LENGTH (expr));
      }
    else
!     memcpy (ptr, TREE_STRING_POINTER (expr), total_bytes);
!   return total_bytes;
  }
  
  
  /* 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.  */
  
  int
! native_encode_expr (const_tree expr, unsigned char *ptr, int len)
  {
    switch (TREE_CODE (expr))
      {
      case INTEGER_CST:
!       return native_encode_int (expr, ptr, len);
  
      case REAL_CST:
!       return native_encode_real (expr, ptr, len);
  
      case FIXED_CST:
!       return native_encode_fixed (expr, ptr, len);
  
      case COMPLEX_CST:
!       return native_encode_complex (expr, ptr, len);
  
      case VECTOR_CST:
!       return native_encode_vector (expr, ptr, len);
  
      case STRING_CST:
!       return native_encode_string (expr, ptr, len);
  
      default:
        return 0;
--- 7448,7503 ----
        || !tree_fits_shwi_p (TYPE_SIZE_UNIT (type)))
      return 0;
    total_bytes = tree_to_shwi (TYPE_SIZE_UNIT (type));
!   if ((off == -1 && total_bytes > len)
!       || off >= total_bytes)
      return 0;
!   if (off == -1)
!     off = 0;
!   if (TREE_STRING_LENGTH (expr) - off < MIN (total_bytes, len))
      {
!       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) + 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.  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, int off)
  {
    switch (TREE_CODE (expr))
      {
      case INTEGER_CST:
!       return native_encode_int (expr, ptr, len, off);
  
      case REAL_CST:
!       return native_encode_real (expr, ptr, len, off);
  
      case FIXED_CST:
!       return native_encode_fixed (expr, ptr, len, off);
  
      case COMPLEX_CST:
!       return native_encode_complex (expr, ptr, len, off);
  
      case VECTOR_CST:
!       return native_encode_vector (expr, ptr, len, off);
  
      case STRING_CST:
!       return native_encode_string (expr, ptr, len, off);
  
      default:
        return 0;
Index: gcc/fold-const.h
===================================================================
*** gcc/fold-const.h.orig       2014-07-11 12:34:03.435274479 +0200
--- gcc/fold-const.h    2014-07-24 12:00:29.662082160 +0200
*************** along with GCC; see the file COPYING3.
*** 25,31 ****
  extern int folding_initializer;
  
  /* Convert between trees and native memory representation.  */
! extern int native_encode_expr (const_tree, unsigned char *, int);
  extern tree native_interpret_expr (tree, const unsigned char *, int);
  
  /* Fold constants as much as possible in an expression.
--- 25,31 ----
  extern int folding_initializer;
  
  /* Convert between trees and native memory representation.  */
! 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: gcc/testsuite/gcc.dg/pr61762.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/pr61762.c      2014-07-24 12:00:36.749081672 +0200
***************
*** 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" } } */
Index: gcc/gimple-fold.c
===================================================================
*** gcc/gimple-fold.c.orig      2014-07-11 12:07:36.508383737 +0200
--- gcc/gimple-fold.c   2014-07-24 12:39:08.639922501 +0200
*************** get_base_constructor (tree base, HOST_WI
*** 2881,2921 ****
      }
  }
  
- /* 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.  */
  
--- 2881,2886 ----
*************** fold_ctor_reference (tree type, tree cto
*** 3107,3114 ****
        STRIP_NOPS (ret);
        return ret;
      }
!   if (TREE_CODE (ctor) == STRING_CST)
!     return fold_string_cst_ctor_reference (type, ctor, offset, size);
    if (TREE_CODE (ctor) == CONSTRUCTOR)
      {
  
--- 3072,3090 ----
        STRIP_NOPS (ret);
        return ret;
      }
!   /* 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: gcc/testsuite/gcc.dg/fold-cstring.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/fold-cstring.c 2014-07-24 12:24:40.375982280 +0200
***************
*** 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;
+ }
Index: gcc/testsuite/gcc.dg/fold-cvect.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/fold-cvect.c   2014-07-24 12:49:16.330880663 +0200
***************
*** 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;
+ }

Reply via email to