Independent on the outcome of the discussion regarding to comparing ADDR_EXPRs in operand_equal_p the following presents a more backportable fix for the SCCVN endless loop. We know that we compare is_gimple_min_invariant addresses which means we can resort to a get_addr_base_and_unit_offset comparison to double-check the operand_equal_p result.
For now I'll revert the previous change to the operand_equal_p behavior. Bootstrap / regtest pending on x86_64-unknown-linux-gnu. Richard. 2013-05-27 Richard Biener <rguent...@suse.de> Revert PR middle-end/57381 * fold-const.c (operand_equal_p): Compare FIELD_DECLs with OEP_CONSTANT_ADDRESS_OF retained. PR tree-optimization/57417 * tree-ssa-sccvn.c (vn_reference_fold_indirect): Fix test for unchanged base. (set_ssa_val_to): Compare addresses using get_addr_base_and_unit_offset. * gcc.dg/torture/pr57417.c: New testcase. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 199350) --- gcc/fold-const.c (working copy) *************** operand_equal_p (const_tree arg0, const_ *** 2664,2673 **** 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. */ ! 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)) --- 2664,2673 ---- 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. */ ! 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: if (!OP_SAME (0)) Index: gcc/tree-ssa-sccvn.c =================================================================== *** gcc/tree-ssa-sccvn.c (revision 199350) --- gcc/tree-ssa-sccvn.c (working copy) *************** vn_reference_fold_indirect (vec<vn_refer *** 1145,1151 **** addr_base = get_addr_base_and_unit_offset (TREE_OPERAND (op->op0, 0), &addr_offset); gcc_checking_assert (addr_base && TREE_CODE (addr_base) != MEM_REF); ! if (addr_base != op->op0) { double_int off = tree_to_double_int (mem_op->op0); off = off.sext (TYPE_PRECISION (TREE_TYPE (mem_op->op0))); --- 1145,1151 ---- addr_base = get_addr_base_and_unit_offset (TREE_OPERAND (op->op0, 0), &addr_offset); gcc_checking_assert (addr_base && TREE_CODE (addr_base) != MEM_REF); ! if (addr_base != TREE_OPERAND (op->op0, 0)) { double_int off = tree_to_double_int (mem_op->op0); off = off.sext (TYPE_PRECISION (TREE_TYPE (mem_op->op0))); *************** static inline bool *** 2608,2613 **** --- 2608,2614 ---- set_ssa_val_to (tree from, tree to) { tree currval = SSA_VAL (from); + HOST_WIDE_INT toff, coff; if (from != to) { *************** set_ssa_val_to (tree from, tree to) *** 2643,2649 **** print_generic_expr (dump_file, to, 0); } ! if (currval != to && !operand_equal_p (currval, to, OEP_PURE_SAME)) { VN_INFO (from)->valnum = to; if (dump_file && (dump_flags & TDF_DETAILS)) --- 2644,2660 ---- print_generic_expr (dump_file, to, 0); } ! if (currval != to ! && !operand_equal_p (currval, to, 0) ! /* ??? For addresses involving volatile objects or types operand_equal_p ! does not reliably detect ADDR_EXPRs as equal. We know we are only ! getting invariant gimple addresses here, so can use ! get_addr_base_and_unit_offset to do this comparison. */ ! && !(TREE_CODE (currval) == ADDR_EXPR ! && TREE_CODE (to) == ADDR_EXPR ! && (get_addr_base_and_unit_offset (TREE_OPERAND (currval, 0), &coff) ! == get_addr_base_and_unit_offset (TREE_OPERAND (to, 0), &toff)) ! && coff == toff)) { VN_INFO (from)->valnum = to; if (dump_file && (dump_flags & TDF_DETAILS)) Index: gcc/testsuite/gcc.dg/torture/pr57417.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr57417.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr57417.c (working copy) *************** *** 0 **** --- 1,12 ---- + /* { dg-do compile } */ + + int a, b; + volatile int *c; + + void foo () + { + volatile int d[1]; + b = 0; + for (;; a--) + c = &d[b]; + }