This first patch improves DSE by improving the handling of references with non-invariant addresses such as a->b[i].c in stmt_kills_ref_p_1.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2014-06-04 Richard Biener <rguent...@suse.de> * tree-ssa-alias.c (stmt_may_clobber_ref_p): Improve handling of accesses with non-invariant address. * gcc.dg/tree-ssa/ssa-dse-16.c: New testcase. Index: gcc/tree-ssa-alias.c =================================================================== *** gcc/tree-ssa-alias.c (revision 211213) --- gcc/tree-ssa-alias.c (working copy) *************** stmt_may_clobber_ref_p (gimple stmt, tre *** 2174,2184 **** static bool stmt_kills_ref_p_1 (gimple stmt, ao_ref *ref) { ! /* For a must-alias check we need to be able to constrain ! the access properly. ! FIXME: except for BUILTIN_FREE. */ ! if (!ao_ref_base (ref) ! || ref->max_size == -1) return false; if (gimple_has_lhs (stmt) --- 2174,2180 ---- static bool stmt_kills_ref_p_1 (gimple stmt, ao_ref *ref) { ! if (!ao_ref_base (ref)) return false; if (gimple_has_lhs (stmt) *************** stmt_kills_ref_p_1 (gimple stmt, ao_ref *** 2191,2199 **** might throw as well. */ && !stmt_can_throw_internal (stmt)) { ! tree base, lhs = gimple_get_lhs (stmt); HOST_WIDE_INT size, offset, max_size, ref_offset = ref->offset; ! base = get_ref_base_and_extent (lhs, &offset, &size, &max_size); /* We can get MEM[symbol: sZ, index: D.8862_1] here, so base == ref->base does not always hold. */ if (base != ref->base) --- 2187,2237 ---- might throw as well. */ && !stmt_can_throw_internal (stmt)) { ! tree lhs = gimple_get_lhs (stmt); ! /* If LHS is literally a base of the access we are done. */ ! if (ref->ref) ! { ! tree base = ref->ref; ! if (handled_component_p (base)) ! { ! tree saved_lhs0 = NULL_TREE; ! if (handled_component_p (lhs)) ! { ! saved_lhs0 = TREE_OPERAND (lhs, 0); ! TREE_OPERAND (lhs, 0) = integer_zero_node; ! } ! do ! { ! /* Just compare the outermost handled component, if ! they are equal we have found a possible common ! base. */ ! tree saved_base0 = TREE_OPERAND (base, 0); ! TREE_OPERAND (base, 0) = integer_zero_node; ! bool res = operand_equal_p (lhs, base, 0); ! TREE_OPERAND (base, 0) = saved_base0; ! if (res) ! break; ! /* Otherwise drop handled components of the access. */ ! base = saved_base0; ! } ! while (handled_component_p (base)); ! 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; ! } ! ! /* Now look for non-literal equal bases with the restriction of ! handling constant offset and size. */ ! /* For a must-alias check we need to be able to constrain ! the access properly. */ ! if (ref->max_size == -1) ! return false; HOST_WIDE_INT size, offset, max_size, ref_offset = ref->offset; ! tree base = get_ref_base_and_extent (lhs, &offset, &size, &max_size); /* We can get MEM[symbol: sZ, index: D.8862_1] here, so base == ref->base does not always hold. */ if (base != ref->base) *************** stmt_kills_ref_p_1 (gimple stmt, ao_ref *** 2261,2266 **** --- 2299,2308 ---- case BUILT_IN_MEMMOVE_CHK: case BUILT_IN_MEMSET_CHK: { + /* For a must-alias check we need to be able to constrain + the access properly. */ + if (ref->max_size == -1) + return false; tree dest = gimple_call_arg (stmt, 0); tree len = gimple_call_arg (stmt, 2); if (!tree_fits_shwi_p (len)) Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-16.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-16.c (revision 0) +++ gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-16.c (working copy) @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dse1-details" } */ + +struct X { struct A { int a[2]; } b[10]; }; +void foo (struct X *x, int i) +{ + struct A a; + /* Confuse SRA here with using a variable index, otherwise it will mess + with the IL too much. */ + a.a[i] = 3; + a.a[1] = 0; + /* The following store is dead. */ + x->b[i].a[0] = 1; + x->b[i] = a; +} + +/* { dg-final { scan-tree-dump "Deleted dead store" "dse1" } } */ +/* { dg-final { cleanup-tree-dump "dse1" } } */