Hi! On the following testcase, VN during free keeps iterating forever, since the unshare_expr call I've added to fix PR55935. The bug is that when we have volatile int a[1]; and &a[0] expression, if we unshare_expr that expression, it doesn't compare operand_equal_p (exp, unshare_expr (exp), OEP_PURE_SAME). While when looking at ADDR_EXPR we set OEP_CONSTANT_ADDRESS_OF flag, when looking at the ARRAY_REF we see it has TREE_SIDE_EFFECTS set and return 0. For ADDR_EXPR of ARRAY_REF or other reference it really doesn't matter whether the ARRAY_REF itself has side-effects or not though, so we should ignore the side-effects.
Fixed thusly, bootstrapped/regtested on x86_64-linux, ok for trunk? 2013-02-26 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/56448 * fold-const.c (operand_equal_p) <case tcc_reference>: Don't look at TREE_SIDE_EFFECTS if flags contain OEP_CONSTANT_ADDRESS_OF. Clear OEP_CONSTANT_ADDRESS_OF from flags before recursing on second or later operands of the references, or even first operand for INDIRECT_REF, TARGET_MEM_REF or MEM_REF. * gcc.c-torture/compile/pr56448.c: New test. --- gcc/fold-const.c.jj 2013-02-08 16:05:34.000000000 +0100 +++ gcc/fold-const.c 2013-02-25 23:25:46.676092462 +0100 @@ -2542,19 +2542,25 @@ operand_equal_p (const_tree arg0, const_ case tcc_reference: /* If either of the pointer (or reference) expressions we are - dereferencing contain a side effect, these cannot be equal. */ - if (TREE_SIDE_EFFECTS (arg0) - || TREE_SIDE_EFFECTS (arg1)) + dereferencing contain a side effect, these cannot be equal, + but their addresses can be. */ + if ((flags & OEP_CONSTANT_ADDRESS_OF) == 0 + && (TREE_SIDE_EFFECTS (arg0) + || TREE_SIDE_EFFECTS (arg1))) return 0; switch (TREE_CODE (arg0)) { case INDIRECT_REF: + flags &= ~OEP_CONSTANT_ADDRESS_OF; + return OP_SAME (0); + case REALPART_EXPR: case IMAGPART_EXPR: 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) @@ -2563,6 +2569,7 @@ operand_equal_p (const_tree arg0, const_ 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 frontent @@ -2581,22 +2588,28 @@ operand_equal_p (const_tree arg0, const_ /* Operands 2 and 3 may be null. Compare the array index by value if it is constant first as we may have different types but same value here. */ - return (OP_SAME (0) - && (tree_int_cst_equal (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 1)) - || OP_SAME (1)) + 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)) && OP_SAME_WITH_NULL (2) && OP_SAME_WITH_NULL (3)); case COMPONENT_REF: /* Handle operand 2 the same as for ARRAY_REF. Operand 0 may be NULL when we're called to compare MEM_EXPRs. */ - return OP_SAME_WITH_NULL (0) - && OP_SAME (1) - && OP_SAME_WITH_NULL (2); + if (!OP_SAME_WITH_NULL (0)) + return 0; + flags &= ~OEP_CONSTANT_ADDRESS_OF; + return OP_SAME (1) && OP_SAME_WITH_NULL (2); case BIT_FIELD_REF: - return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); + if (!OP_SAME (0)) + return 0; + flags &= ~OEP_CONSTANT_ADDRESS_OF; + return OP_SAME (1) && OP_SAME (2); default: return 0; --- gcc/testsuite/gcc.c-torture/compile/pr56448.c.jj 2013-02-25 23:31:55.266922056 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr56448.c 2013-02-25 23:29:55.000000000 +0100 @@ -0,0 +1,14 @@ +/* PR tree-optimization/56448 */ + +volatile int a[1]; +int b; + +void +foo () +{ + for (;;) + { + int *c[3][6] = { 0, 0, 0, &b, 0, 0, 0, 0, &b, 0, 0, 0, 0, 0, 0, 0, &b, (int *) &a[0] }; + b = *c[2][5]; + } +} Jakub