This fixes PR49079 - the mem-ref merge broke the trailing
array access detection of get_ref_base_and_extent because of the
embedding of a view-conversion.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to
trunk and branch.

Richard.

2011-05-20  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/49079
        * tree-dfa.c (get_ref_base_and_extent): Handle view-converting
        MEM_REFs correctly for the trailing array access detection.
        Special case constants the same way as decls for overall size
        constraining.

        * gcc.dg/torture/pr49079.c: New testcase.

Index: gcc/tree-dfa.c
===================================================================
*** gcc/tree-dfa.c      (revision 173939)
--- gcc/tree-dfa.c      (working copy)
*************** get_ref_base_and_extent (tree exp, HOST_
*** 709,714 ****
--- 709,715 ----
    tree size_tree = NULL_TREE;
    HOST_WIDE_INT bit_offset = 0;
    bool seen_variable_array_ref = false;
+   tree base_type;
  
    /* First get the final access size from just the outermost expression.  */
    if (TREE_CODE (exp) == COMPONENT_REF)
*************** get_ref_base_and_extent (tree exp, HOST_
*** 739,744 ****
--- 740,747 ----
       and find the ultimate containing object.  */
    while (1)
      {
+       base_type = TREE_TYPE (exp);
+ 
        switch (TREE_CODE (exp))
        {
        case BIT_FIELD_REF:
*************** get_ref_base_and_extent (tree exp, HOST_
*** 926,934 ****
       the array.  The simplest way to conservatively deal with this
       is to punt in the case that offset + maxsize reaches the
       base type boundary.  This needs to include possible trailing padding
!      that is there for alignment purposes.
  
!      That is of course only true if the base object is not a decl.  */
  
    if (DECL_P (exp))
      {
--- 929,944 ----
       the array.  The simplest way to conservatively deal with this
       is to punt in the case that offset + maxsize reaches the
       base type boundary.  This needs to include possible trailing padding
!      that is there for alignment purposes.  */
! 
!   if (seen_variable_array_ref
!       && maxsize != -1
!       && (!host_integerp (TYPE_SIZE (base_type), 1)
!         || (bit_offset + maxsize
!             == (signed) TREE_INT_CST_LOW (TYPE_SIZE (base_type)))))
!     maxsize = -1;
  
!   /* In case of a decl or constant base object we can do better.  */
  
    if (DECL_P (exp))
      {
*************** get_ref_base_and_extent (tree exp, HOST_
*** 938,949 ****
          && host_integerp (DECL_SIZE (exp), 1))
        maxsize = TREE_INT_CST_LOW (DECL_SIZE (exp)) - bit_offset;
      }
!   else if (seen_variable_array_ref
!          && maxsize != -1
!          && (!host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
!              || (bit_offset + maxsize
!                  == (signed) TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))))))
!     maxsize = -1;
  
    /* ???  Due to negative offsets in ARRAY_REF we can end up with
       negative bit_offset here.  We might want to store a zero offset
--- 948,961 ----
          && host_integerp (DECL_SIZE (exp), 1))
        maxsize = TREE_INT_CST_LOW (DECL_SIZE (exp)) - bit_offset;
      }
!   else if (CONSTANT_CLASS_P (exp))
!     {
!       /* If maxsize is unknown adjust it according to the size of the
!          base type constant.  */
!       if (maxsize == -1
!         && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1))
!       maxsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))) - bit_offset;
!     }
  
    /* ???  Due to negative offsets in ARRAY_REF we can end up with
       negative bit_offset here.  We might want to store a zero offset
Index: gcc/testsuite/gcc.dg/torture/pr49079.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr49079.c      (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr49079.c      (revision 0)
***************
*** 0 ****
--- 1,31 ----
+ /* { dg-do run } */
+ 
+ extern void abort (void);
+ 
+ struct Ustr
+ {
+   unsigned char data[1];
+ };
+ 
+ static unsigned int
+ ustr_xi__embed_val_get(const unsigned char *data)
+ {
+   return (unsigned int)data[0];
+ }
+ 
+ int __attribute__((noinline)) zero(void) { return 0; }
+ 
+ static unsigned int
+ ustr_len(const struct Ustr *s1)
+ {
+   return ustr_xi__embed_val_get(s1->data + 1 + zero());
+ }
+ 
+ int
+ main()
+ {
+   if (ustr_len (((struct Ustr *) "\x01" "\x0002" "s2")) != 2)
+     abort ();
+ 
+   return 0;
+ }

Reply via email to