This fixes tail-merging and folding related wrong-code regressions
caused by ignoring alignment of memory references.  It introduces
OEP_ADDRESS_OF (in addition to OEP_CONSTANT_ADDRESS_OF) to not
hurt the cases where we are only interested in addresses.

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

Richard.

2015-03-09  Richard Biener  <rguent...@suse.de>

        PR middle-end/65270
        * tree-core.h (enum operand_equal_flag): Add OEP_ADDRESS_OF.
        * fold-const.c (operand_equal_p): When recursing for ADDR_EXPRs
        operand set OEP_ADDRESS_OF.  Clear it when recursing to non-bases
        of that.  When comparing dereferences compare alignment.
        When comparing MEM_REFs or TARGET_MEM_REFs compare dependence info.

        * gcc.dg/torture/pr65270-1.c: New testcase.
        * gcc.dg/torture/pr65270-2.c: Likewise. 

Index: gcc/tree-core.h
===================================================================
*** gcc/tree-core.h     (revision 221277)
--- gcc/tree-core.h     (working copy)
*************** enum size_type_kind {
*** 700,706 ****
  enum operand_equal_flag {
    OEP_ONLY_CONST = 1,
    OEP_PURE_SAME = 2,
!   OEP_CONSTANT_ADDRESS_OF = 4
  };
  
  /* Enum and arrays used for tree allocation stats.
--- 700,707 ----
  enum operand_equal_flag {
    OEP_ONLY_CONST = 1,
    OEP_PURE_SAME = 2,
!   OEP_CONSTANT_ADDRESS_OF = 4,
!   OEP_ADDRESS_OF = 8
  };
  
  /* Enum and arrays used for tree allocation stats.
Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c    (revision 221277)
--- gcc/fold-const.c    (working copy)
*************** operand_equal_p (const_tree arg0, const_
*** 2860,2866 ****
        case ADDR_EXPR:
        return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
                                TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)
!                               ? OEP_CONSTANT_ADDRESS_OF : 0);
        default:
        break;
        }
--- 2867,2873 ----
        case ADDR_EXPR:
        return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
                                TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)
!                               ? OEP_CONSTANT_ADDRESS_OF | OEP_ADDRESS_OF : 0);
        default:
        break;
        }
*************** operand_equal_p (const_tree arg0, const_
*** 2922,2928 ****
        switch (TREE_CODE (arg0))
        {
        case INDIRECT_REF:
!         flags &= ~OEP_CONSTANT_ADDRESS_OF;
          return OP_SAME (0);
  
        case REALPART_EXPR:
--- 2929,2939 ----
        switch (TREE_CODE (arg0))
        {
        case INDIRECT_REF:
!         if (!(flags & OEP_ADDRESS_OF)
!             && (TYPE_ALIGN (TREE_TYPE (arg0))
!                 != TYPE_ALIGN (TREE_TYPE (arg1))))
!           return 0;
!         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return OP_SAME (0);
  
        case REALPART_EXPR:
*************** operand_equal_p (const_tree arg0, const_
*** 2930,2936 ****
          return OP_SAME (0);
  
        case TARGET_MEM_REF:
!         flags &= ~OEP_CONSTANT_ADDRESS_OF;
          /* Require equal extra operands and then fall through to MEM_REF
             handling of the two common operands.  */
          if (!OP_SAME_WITH_NULL (2)
--- 2941,2947 ----
          return OP_SAME (0);
  
        case TARGET_MEM_REF:
!         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          /* Require equal extra operands and then fall through to MEM_REF
             handling of the two common operands.  */
          if (!OP_SAME_WITH_NULL (2)
*************** operand_equal_p (const_tree arg0, const_
*** 2939,2945 ****
            return 0;
          /* Fallthru.  */
        case MEM_REF:
!         flags &= ~OEP_CONSTANT_ADDRESS_OF;
          /* Require equal access sizes, and similar pointer types.
             We can have incomplete types for array references of
             variable-sized arrays from the Fortran frontend
--- 2950,2956 ----
            return 0;
          /* Fallthru.  */
        case MEM_REF:
!         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          /* Require equal access sizes, and similar pointer types.
             We can have incomplete types for array references of
             variable-sized arrays from the Fortran frontend
*************** operand_equal_p (const_tree arg0, const_
*** 2950,2958 ****
                       && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
                                           TYPE_SIZE (TREE_TYPE (arg1)), 
flags)))
                  && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
!                 && alias_ptr_types_compatible_p
!                      (TREE_TYPE (TREE_OPERAND (arg0, 1)),
!                       TREE_TYPE (TREE_OPERAND (arg1, 1)))
                  && OP_SAME (0) && OP_SAME (1));
  
        case ARRAY_REF:
--- 2961,2976 ----
                       && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
                                           TYPE_SIZE (TREE_TYPE (arg1)), 
flags)))
                  && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
!                 && ((flags & OEP_ADDRESS_OF)
!                     || (alias_ptr_types_compatible_p
!                           (TREE_TYPE (TREE_OPERAND (arg0, 1)),
!                            TREE_TYPE (TREE_OPERAND (arg1, 1)))
!                         && (MR_DEPENDENCE_CLIQUE (arg0)
!                             == MR_DEPENDENCE_CLIQUE (arg1))
!                         && (MR_DEPENDENCE_BASE (arg0)
!                             == MR_DEPENDENCE_BASE (arg1))
!                         && (TYPE_ALIGN (TREE_TYPE (arg0))
!                             == TYPE_ALIGN (TREE_TYPE (arg1)))))
                  && OP_SAME (0) && OP_SAME (1));
  
        case ARRAY_REF:
*************** operand_equal_p (const_tree arg0, const_
*** 2962,2968 ****
             may have different types but same value here.  */
          if (!OP_SAME (0))
            return 0;
!         flags &= ~OEP_CONSTANT_ADDRESS_OF;
          return ((tree_int_cst_equal (TREE_OPERAND (arg0, 1),
                                       TREE_OPERAND (arg1, 1))
                   || OP_SAME (1))
--- 2980,2986 ----
             may have different types but same value here.  */
          if (!OP_SAME (0))
            return 0;
!         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return ((tree_int_cst_equal (TREE_OPERAND (arg0, 1),
                                       TREE_OPERAND (arg1, 1))
                   || OP_SAME (1))
*************** operand_equal_p (const_tree arg0, const_
*** 2975,2987 ****
          if (!OP_SAME_WITH_NULL (0)
              || !OP_SAME (1))
            return 0;
!         flags &= ~OEP_CONSTANT_ADDRESS_OF;
          return OP_SAME_WITH_NULL (2);
  
        case BIT_FIELD_REF:
          if (!OP_SAME (0))
            return 0;
!         flags &= ~OEP_CONSTANT_ADDRESS_OF;
          return OP_SAME (1) && OP_SAME (2);
  
        default:
--- 2993,3005 ----
          if (!OP_SAME_WITH_NULL (0)
              || !OP_SAME (1))
            return 0;
!         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return OP_SAME_WITH_NULL (2);
  
        case BIT_FIELD_REF:
          if (!OP_SAME (0))
            return 0;
!         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
          return OP_SAME (1) && OP_SAME (2);
  
        default:
*************** operand_equal_p (const_tree arg0, const_
*** 2992,2997 ****
--- 3010,3019 ----
        switch (TREE_CODE (arg0))
        {
        case ADDR_EXPR:
+         return operand_equal_p (TREE_OPERAND (arg0, 0),
+                                 TREE_OPERAND (arg1, 0),
+                                 flags | OEP_ADDRESS_OF);
+ 
        case TRUTH_NOT_EXPR:
          return OP_SAME (0);
  
Index: gcc/testsuite/gcc.dg/torture/pr65270-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr65270-1.c    (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr65270-1.c    (working copy)
***************
*** 0 ****
--- 1,32 ----
+ /* { dg-do run } */
+ 
+ struct a 
+ {
+   int a[100];
+ };
+ typedef struct a misaligned_t __attribute__ ((aligned (8)));
+ typedef struct a aligned_t __attribute__ ((aligned (32)));
+ 
+ __attribute__ ((used))
+ __attribute__ ((noinline))
+ void
+ t(void *a, int misaligned, aligned_t *d)
+ {
+   int i,v;
+   for (i=0;i<100;i++)
+     {
+       if (misaligned)
+       v=((misaligned_t *)a)->a[i];
+       else
+       v=((aligned_t *)a)->a[i];
+       d->a[i]+=v;
+     }
+ }
+ struct b {int v; misaligned_t m;aligned_t aa;} b;
+ aligned_t d;
+ int
+ main()
+ {
+   t(&b.m, 1, &d);
+   return 0;
+ }
Index: gcc/testsuite/gcc.dg/torture/pr65270-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr65270-2.c    (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr65270-2.c    (working copy)
***************
*** 0 ****
--- 1,26 ----
+ /* { dg-do run } */
+ 
+ struct a 
+ {
+   int a[100];
+ };
+ typedef struct a misaligned_t __attribute__ ((aligned (8)));
+ typedef struct a aligned_t __attribute__ ((aligned (32)));
+ 
+ __attribute__ ((used))
+ __attribute__ ((noinline))
+ void
+ t(void *a, int misaligned, aligned_t *d)
+ {
+   int i,v;
+   for (i=0;i<100;i++)
+     d->a[i]+=!misaligned? ((aligned_t *)a)->a[i] : ((misaligned_t *)a)->a[i];
+ }
+ struct b {int v; misaligned_t m;aligned_t aa;} b;
+ aligned_t d;
+ int
+ main()
+ {
+   t(&b.m, 1, &d);
+   return 0;
+ }

Reply via email to