This patch fixes PR49770 by introducing an indicator whether it's worth to lose some TBAA in favor of using existing valueization. Simple for now - always make sure use the valueized variant if that is in any way different from the unvalueized one.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2011-07-21 Richard Guenther <rguent...@suse.de> PR tree-optimization/49770 * tree-ssa-sccvn.c (valueize_refs_1): Return whether we valueized any operand. Renamed from ... (valueize_refs): ... this. New wrapper around valueize_refs_1. (valueize_shared_reference_ops_from_ref): Return whether we valueized any operand. (vn_reference_lookup): Only when we valueized any operand use the valueized reference for alias analysis. Do not preserve the original reference tree in this case. * g++.dg/torture/pr49770.C: New testcase. Index: gcc/tree-ssa-sccvn.c =================================================================== *** gcc/tree-ssa-sccvn.c (revision 176554) --- gcc/tree-ssa-sccvn.c (working copy) *************** fully_constant_vn_reference_p (vn_refere *** 1146,1174 **** /* Transform any SSA_NAME's in a vector of vn_reference_op_s structures into their value numbers. This is done in-place, and ! the vector passed in is returned. */ static VEC (vn_reference_op_s, heap) * ! valueize_refs (VEC (vn_reference_op_s, heap) *orig) { vn_reference_op_t vro; unsigned int i; FOR_EACH_VEC_ELT (vn_reference_op_s, orig, i, vro) { if (vro->opcode == SSA_NAME || (vro->op0 && TREE_CODE (vro->op0) == SSA_NAME)) { ! vro->op0 = SSA_VAL (vro->op0); /* If it transforms from an SSA_NAME to a constant, update the opcode. */ if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME) vro->opcode = TREE_CODE (vro->op0); } if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME) ! vro->op1 = SSA_VAL (vro->op1); if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME) ! vro->op2 = SSA_VAL (vro->op2); /* If it transforms from an SSA_NAME to an address, fold with a preceding indirect reference. */ if (i > 0 --- 1146,1196 ---- /* Transform any SSA_NAME's in a vector of vn_reference_op_s structures into their value numbers. This is done in-place, and ! the vector passed in is returned. *VALUEIZED_ANYTHING will specify ! whether any operands were valueized. */ static VEC (vn_reference_op_s, heap) * ! valueize_refs_1 (VEC (vn_reference_op_s, heap) *orig, bool *valueized_anything) { vn_reference_op_t vro; unsigned int i; + *valueized_anything = false; + FOR_EACH_VEC_ELT (vn_reference_op_s, orig, i, vro) { if (vro->opcode == SSA_NAME || (vro->op0 && TREE_CODE (vro->op0) == SSA_NAME)) { ! tree tem = SSA_VAL (vro->op0); ! if (tem != vro->op0) ! { ! *valueized_anything = true; ! vro->op0 = tem; ! } /* If it transforms from an SSA_NAME to a constant, update the opcode. */ if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME) vro->opcode = TREE_CODE (vro->op0); } if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME) ! { ! tree tem = SSA_VAL (vro->op1); ! if (tem != vro->op1) ! { ! *valueized_anything = true; ! vro->op1 = tem; ! } ! } if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME) ! { ! tree tem = SSA_VAL (vro->op2); ! if (tem != vro->op2) ! { ! *valueized_anything = true; ! vro->op2 = tem; ! } ! } /* If it transforms from an SSA_NAME to an address, fold with a preceding indirect reference. */ if (i > 0 *************** valueize_refs (VEC (vn_reference_op_s, h *** 1203,1222 **** return orig; } static VEC(vn_reference_op_s, heap) *shared_lookup_references; /* Create a vector of vn_reference_op_s structures from REF, a REFERENCE_CLASS_P tree. The vector is shared among all callers of ! this function. */ static VEC(vn_reference_op_s, heap) * ! valueize_shared_reference_ops_from_ref (tree ref) { if (!ref) return NULL; VEC_truncate (vn_reference_op_s, shared_lookup_references, 0); copy_reference_ops_from_ref (ref, &shared_lookup_references); ! shared_lookup_references = valueize_refs (shared_lookup_references); return shared_lookup_references; } --- 1225,1253 ---- return orig; } + static VEC (vn_reference_op_s, heap) * + valueize_refs (VEC (vn_reference_op_s, heap) *orig) + { + bool tem; + return valueize_refs_1 (orig, &tem); + } + static VEC(vn_reference_op_s, heap) *shared_lookup_references; /* Create a vector of vn_reference_op_s structures from REF, a REFERENCE_CLASS_P tree. The vector is shared among all callers of ! this function. *VALUEIZED_ANYTHING will specify whether any ! operands were valueized. */ static VEC(vn_reference_op_s, heap) * ! valueize_shared_reference_ops_from_ref (tree ref, bool *valueized_anything) { if (!ref) return NULL; VEC_truncate (vn_reference_op_s, shared_lookup_references, 0); copy_reference_ops_from_ref (ref, &shared_lookup_references); ! shared_lookup_references = valueize_refs_1 (shared_lookup_references, ! valueized_anything); return shared_lookup_references; } *************** vn_reference_lookup (tree op, tree vuse, *** 1694,1705 **** VEC (vn_reference_op_s, heap) *operands; struct vn_reference_s vr1; tree cst; if (vnresult) *vnresult = NULL; vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE; ! vr1.operands = operands = valueize_shared_reference_ops_from_ref (op); vr1.type = TREE_TYPE (op); vr1.set = get_alias_set (op); vr1.hashcode = vn_reference_compute_hash (&vr1); --- 1725,1738 ---- VEC (vn_reference_op_s, heap) *operands; struct vn_reference_s vr1; tree cst; + bool valuezied_anything; if (vnresult) *vnresult = NULL; vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE; ! vr1.operands = operands ! = valueize_shared_reference_ops_from_ref (op, &valuezied_anything); vr1.type = TREE_TYPE (op); vr1.set = get_alias_set (op); vr1.hashcode = vn_reference_compute_hash (&vr1); *************** vn_reference_lookup (tree op, tree vuse, *** 1711,1722 **** { vn_reference_t wvnresult; ao_ref r; ! /* Make sure to use a valueized reference ... */ ! if (!ao_ref_init_from_vn_reference (&r, vr1.set, vr1.type, vr1.operands)) ao_ref_init (&r, op); - else - /* ... but also preserve a full reference tree for advanced TBAA. */ - r.ref = op; vn_walk_kind = kind; wvnresult = (vn_reference_t)walk_non_aliased_vuses (&r, vr1.vuse, --- 1744,1755 ---- { vn_reference_t wvnresult; ao_ref r; ! /* Make sure to use a valueized reference if we valueized anything. ! Otherwise preserve the full reference for advanced TBAA. */ ! if (!valuezied_anything ! || !ao_ref_init_from_vn_reference (&r, vr1.set, vr1.type, ! vr1.operands)) ao_ref_init (&r, op); vn_walk_kind = kind; wvnresult = (vn_reference_t)walk_non_aliased_vuses (&r, vr1.vuse, Index: gcc/testsuite/g++.dg/torture/pr49770.C =================================================================== *** gcc/testsuite/g++.dg/torture/pr49770.C (revision 0) --- gcc/testsuite/g++.dg/torture/pr49770.C (revision 0) *************** *** 0 **** --- 1,86 ---- + /* { dg-do run } */ + /* { dg-options "-std=c++0x -fno-tree-forwprop" } */ + + typedef __SIZE_TYPE__ size_t; + + template < typename > struct remove_reference; + template < typename _Tp > struct remove_reference <_Tp & > + { + typedef _Tp type; + }; + template < typename _Tp > typename remove_reference < _Tp >::type && + move (_Tp && __t) + { + return static_cast < typename remove_reference < _Tp >::type && >(__t); + } + + template < typename _Tp > void + stdswap (_Tp & __a, _Tp & __b) + { + _Tp __tmp (__a); + __a = (__b); + __b = (__tmp); + } + + struct _Deque_iterator + { + int *_M_cur; + int *_M_first; + int *_M_last; + int **_M_node; + }; + + static inline int operatorMIN (_Deque_iterator & __x, _Deque_iterator & __y) + { + return sizeof (int) * (__x._M_node - __y._M_node - 1) + + (__x._M_cur - __x._M_first) + (__y._M_last - __y._M_cur); + } + + struct deque + { + deque & operator = (deque && __x) + { + stdswap (_M_finish, __x._M_finish); + return *this; + } + size_t size () + { + return operatorMIN (_M_finish, _M_start); + } + + deque (): + _M_map (), _M_map_size (), _M_start (), _M_finish () + { + _M_start._M_last = _M_start._M_first + sizeof (int); + } + + int **_M_map; + size_t _M_map_size; + _Deque_iterator _M_start; + _Deque_iterator _M_finish; + }; + + struct queue + { + deque c; + size_t size () + { + return c.size (); + } + }; + + void + test01 () + { + queue a, b; + ++a.c._M_finish._M_cur; + b = move (a); + if (!b.size ()) + __builtin_abort (); + } + + main () + { + test01 (); + } +