struct X { int i; int j; }; struct X a[128]; int foo (int i) { struct X x; x.i = i; x.j = 0; a[i] = x; return a[i].i; } should ideally optimize to return i; But first, FRE is confused by SRA: <bb 2>: _4 = &a[i_2(D)]; MEM[(struct X *)_4] = i_2(D); MEM[(struct X *)_4 + 4B] = 0; _6 = a[i_2(D)].i; return _6; and second (if SRA is disabled), <bb 2>: x.i = i_2(D); x.j = 0; a[i_2(D)] = x; _6 = a[i_2(D)].i; x ={v} {CLOBBER}; return _6; the aggregate copy lookthrough code is too simple here (offset-based stuff just bails out with variable indexes). Using stmt_kills_ref_p helps for this case but it does not for the testcase in PR66142. @@ -1879,7 +1895,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree || handled_component_p (gimple_assign_rhs1 (def_stmt)))) { tree base2; - HOST_WIDE_INT offset2, size2, maxsize2; + HOST_WIDE_INT maxsize2; int i, j; auto_vec<vn_reference_op_s> rhs; vn_reference_op_t vro; @@ -1890,8 +1906,6 @@ vn_reference_lookup_3 (ao_ref *ref, tree /* 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 @@ -1900,8 +1914,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree || 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) + || !stmt_kills_ref_p (def_stmt, ref)) return (void *)-1; /* Find the common base of ref and the lhs. lhs_ops already
Works now with -fno-tree-sra as the patch was committed but SRA still confuses FRE so this is a testcase for the "stupid address-forwarding" issue.
Fixed in GCC 10+.