The following patch fixes PR66142 up to the point where we run into a alias disambiguation issue. One step at a time...
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2015-09-18 Richard Biener <rguent...@suse.de> PR tree-optimization/66142 * fold-const.c (operand_equal_p): When OEP_ADDRESS_OF treat MEM[&x] and x the same. * tree-ssa-sccvn.h (vn_reference_fold_indirect): Remove. * tree-ssa-sccvn.c (vn_reference_fold_indirect): Return true when we simplified sth. (vn_reference_maybe_forwprop_address): Likewise. (valueize_refs_1): When we simplified through vn_reference_fold_indirect or vn_reference_maybe_forwprop_address set valueized_anything to true. (vn_reference_lookup_3): Use stmt_kills_ref_p to see whether one ref kills the other instead of just a offset-based test. * tree-ssa-alias.c (stmt_kills_ref_p): Use OEP_ADDRESS_OF for the operand_equal_p test to compare bases and also compare sizes. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 227859) --- gcc/fold-const.c (working copy) *************** operand_equal_p (const_tree arg0, const_ *** 2752,2761 **** TREE_OPERAND (arg1, 0), flags); } ! if (TREE_CODE (arg0) != TREE_CODE (arg1) /* NOP_EXPR and CONVERT_EXPR are considered equal. */ ! && !(CONVERT_EXPR_P (arg0) && CONVERT_EXPR_P (arg1))) ! return 0; /* This is needed for conversions and for COMPONENT_REF. Might as well play it safe and always test this. */ --- 2759,2791 ---- TREE_OPERAND (arg1, 0), flags); } ! if (TREE_CODE (arg0) != TREE_CODE (arg1)) ! { /* NOP_EXPR and CONVERT_EXPR are considered equal. */ ! if (CONVERT_EXPR_P (arg0) && CONVERT_EXPR_P (arg1)) ! ; ! else if (flags & OEP_ADDRESS_OF) ! { ! /* If we are interested in comparing addresses ignore ! MEM_REF wrappings of the base that can appear just for ! TBAA reasons. */ ! if (TREE_CODE (arg0) == MEM_REF ! && DECL_P (arg1) ! && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR ! && TREE_OPERAND (TREE_OPERAND (arg0, 0), 0) == arg1 ! && integer_zerop (TREE_OPERAND (arg0, 1))) ! return 1; ! else if (TREE_CODE (arg1) == MEM_REF ! && DECL_P (arg0) ! && TREE_CODE (TREE_OPERAND (arg1, 0)) == ADDR_EXPR ! && TREE_OPERAND (TREE_OPERAND (arg1, 0), 0) == arg0 ! && integer_zerop (TREE_OPERAND (arg1, 1))) ! return 1; ! return 0; ! } ! else ! return 0; ! } /* This is needed for conversions and for COMPONENT_REF. Might as well play it safe and always test this. */ Index: gcc/tree-ssa-sccvn.h =================================================================== *** gcc/tree-ssa-sccvn.h (revision 227859) --- gcc/tree-ssa-sccvn.h (working copy) *************** vn_nary_op_t vn_nary_op_insert (tree, tr *** 204,211 **** vn_nary_op_t vn_nary_op_insert_stmt (gimple, tree); vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code, tree, tree *, tree, unsigned int); - void vn_reference_fold_indirect (vec<vn_reference_op_s> *, - unsigned int *); bool ao_ref_init_from_vn_reference (ao_ref *, alias_set_type, tree, vec<vn_reference_op_s> ); tree vn_reference_lookup_pieces (tree, alias_set_type, tree, --- 204,209 ---- Index: gcc/tree-ssa-sccvn.c =================================================================== *** gcc/tree-ssa-sccvn.c (revision 227859) --- gcc/tree-ssa-sccvn.c (working copy) *************** copy_reference_ops_from_call (gcall *cal *** 1184,1190 **** /* Fold *& at position *I_P in a vn_reference_op_s vector *OPS. Updates *I_P to point to the last element of the replacement. */ ! void vn_reference_fold_indirect (vec<vn_reference_op_s> *ops, unsigned int *i_p) { --- 1200,1206 ---- /* Fold *& at position *I_P in a vn_reference_op_s vector *OPS. Updates *I_P to point to the last element of the replacement. */ ! static bool vn_reference_fold_indirect (vec<vn_reference_op_s> *ops, unsigned int *i_p) { *************** vn_reference_fold_indirect (vec<vn_refer *** 1210,1221 **** mem_op->off = tree_to_shwi (mem_op->op0); else mem_op->off = -1; } } /* Fold *& at position *I_P in a vn_reference_op_s vector *OPS. Updates *I_P to point to the last element of the replacement. */ ! static void vn_reference_maybe_forwprop_address (vec<vn_reference_op_s> *ops, unsigned int *i_p) { --- 1226,1239 ---- mem_op->off = tree_to_shwi (mem_op->op0); else mem_op->off = -1; + return true; } + return false; } /* Fold *& at position *I_P in a vn_reference_op_s vector *OPS. Updates *I_P to point to the last element of the replacement. */ ! static bool vn_reference_maybe_forwprop_address (vec<vn_reference_op_s> *ops, unsigned int *i_p) { *************** vn_reference_maybe_forwprop_address (vec *** 1228,1239 **** def_stmt = SSA_NAME_DEF_STMT (op->op0); if (!is_gimple_assign (def_stmt)) ! return; code = gimple_assign_rhs_code (def_stmt); if (code != ADDR_EXPR && code != POINTER_PLUS_EXPR) ! return; off = offset_int::from (mem_op->op0, SIGNED); --- 1246,1257 ---- def_stmt = SSA_NAME_DEF_STMT (op->op0); if (!is_gimple_assign (def_stmt)) ! return false; code = gimple_assign_rhs_code (def_stmt); if (code != ADDR_EXPR && code != POINTER_PLUS_EXPR) ! return false; off = offset_int::from (mem_op->op0, SIGNED); *************** vn_reference_maybe_forwprop_address (vec *** 1265,1275 **** ops->pop (); ops->safe_splice (tem); --*i_p; ! return; } if (!addr_base || TREE_CODE (addr_base) != MEM_REF) ! return; off += addr_offset; off += mem_ref_offset (addr_base); --- 1283,1293 ---- ops->pop (); ops->safe_splice (tem); --*i_p; ! return true; } if (!addr_base || TREE_CODE (addr_base) != MEM_REF) ! return false; off += addr_offset; off += mem_ref_offset (addr_base); *************** vn_reference_maybe_forwprop_address (vec *** 1282,1288 **** ptroff = gimple_assign_rhs2 (def_stmt); if (TREE_CODE (ptr) != SSA_NAME || TREE_CODE (ptroff) != INTEGER_CST) ! return; off += wi::to_offset (ptroff); op->op0 = ptr; --- 1300,1306 ---- ptroff = gimple_assign_rhs2 (def_stmt); if (TREE_CODE (ptr) != SSA_NAME || TREE_CODE (ptroff) != INTEGER_CST) ! return false; off += wi::to_offset (ptroff); op->op0 = ptr; *************** vn_reference_maybe_forwprop_address (vec *** 1303,1308 **** --- 1321,1327 ---- vn_reference_maybe_forwprop_address (ops, i_p); else if (TREE_CODE (op->op0) == ADDR_EXPR) vn_reference_fold_indirect (ops, i_p); + return true; } /* Optimize the reference REF to a constant if possible or return *************** valueize_refs_1 (vec<vn_reference_op_s> *** 1475,1485 **** && vro->op0 && TREE_CODE (vro->op0) == ADDR_EXPR && orig[i - 1].opcode == MEM_REF) ! vn_reference_fold_indirect (&orig, &i); else if (i > 0 && vro->opcode == SSA_NAME && orig[i - 1].opcode == MEM_REF) ! vn_reference_maybe_forwprop_address (&orig, &i); /* If it transforms a non-constant ARRAY_REF into a constant one, adjust the constant offset. */ else if (vro->opcode == ARRAY_REF --- 1494,1510 ---- && vro->op0 && TREE_CODE (vro->op0) == ADDR_EXPR && orig[i - 1].opcode == MEM_REF) ! { ! if (vn_reference_fold_indirect (&orig, &i)) ! *valueized_anything = true; ! } else if (i > 0 && vro->opcode == SSA_NAME && orig[i - 1].opcode == MEM_REF) ! { ! if (vn_reference_maybe_forwprop_address (&orig, &i)) ! *valueized_anything = true; ! } /* If it transforms a non-constant ARRAY_REF into a constant one, adjust the constant offset. */ else if (vro->opcode == ARRAY_REF *************** vn_reference_lookup_3 (ao_ref *ref, tree *** 1880,1886 **** || handled_component_p (gimple_assign_rhs1 (def_stmt)))) { tree base2; ! HOST_WIDE_INT offset2, size2, maxsize2; int i, j; auto_vec<vn_reference_op_s> rhs; vn_reference_op_t vro; --- 1948,1954 ---- || handled_component_p (gimple_assign_rhs1 (def_stmt)))) { tree base2; ! HOST_WIDE_INT maxsize2; int i, j; auto_vec<vn_reference_op_s> rhs; vn_reference_op_t vro; *************** vn_reference_lookup_3 (ao_ref *ref, tree *** 1891,1898 **** /* See if the assignment kills REF. */ base2 = ao_ref_base (&lhs_ref); - offset2 = lhs_ref.offset; - size2 = lhs_ref.size; maxsize2 = lhs_ref.max_size; if (maxsize2 == -1 || (base != base2 --- 1959,1964 ---- *************** vn_reference_lookup_3 (ao_ref *ref, tree *** 1901,1908 **** || TREE_OPERAND (base, 0) != TREE_OPERAND (base2, 0) || !tree_int_cst_equal (TREE_OPERAND (base, 1), TREE_OPERAND (base2, 1)))) ! || offset2 > offset ! || offset2 + size2 < offset + maxsize) return (void *)-1; /* Find the common base of ref and the lhs. lhs_ops already --- 1967,1973 ---- || TREE_OPERAND (base, 0) != TREE_OPERAND (base2, 0) || !tree_int_cst_equal (TREE_OPERAND (base, 1), TREE_OPERAND (base2, 1)))) ! || !stmt_kills_ref_p (def_stmt, ref)) return (void *)-1; /* Find the common base of ref and the lhs. lhs_ops already Index: gcc/tree-ssa-alias.c =================================================================== *** gcc/tree-ssa-alias.c (revision 227859) --- gcc/tree-ssa-alias.c (working copy) *************** stmt_kills_ref_p (gimple stmt, ao_ref *r *** 2282,2290 **** if (saved_lhs0) TREE_OPERAND (lhs, 0) = saved_lhs0; } ! /* Finally check if lhs is equal or equal to the base candidate ! of the access. */ ! if (operand_equal_p (lhs, base, 0)) return true; } --- 2306,2321 ---- if (saved_lhs0) TREE_OPERAND (lhs, 0) = saved_lhs0; } ! /* Finally check if the lhs has the same address and size as the ! base candidate of the access. */ ! if (lhs == base ! || (((TYPE_SIZE (TREE_TYPE (lhs)) ! == TYPE_SIZE (TREE_TYPE (base))) ! || (TYPE_SIZE (TREE_TYPE (lhs)) ! && TYPE_SIZE (TREE_TYPE (base)) ! && operand_equal_p (TYPE_SIZE (TREE_TYPE (lhs)), ! TYPE_SIZE (TREE_TYPE (base)), 0))) ! && operand_equal_p (lhs, base, OEP_ADDRESS_OF))) return true; }