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; + }