The following patch fixes PR84003 where RTL DSE removes a redundant store (a store storing the same value as an earlier store) but in doing this changing program semantics because the later store changes the effective type of the memory location. This in turn allows sched2 to do an originally invalid transform.
The fix is to harden DSE so that while removing the later store the earlier stores alias-sets are changed to reflect both dynamic types - which means using alias-set zero. On GIMPLE we simply avoid removing such type-changing stores because we cannot easily get hold on the earlier store. Bootstrap and regtest running on x86_64-unknown-linux-gnu. Disclaimer: this is a "local" fix, I didn't try to understand much of the DSE data structures but only learned from +-10 lines around the affected transform which I found by searching for the dumped messages ... Richard, you contributed the pass so please review. Ok for trunk and branches? Thanks, Richard. 2018-01-25 Richard Biener <rguent...@suse.de> PR rtl-optimization/84003 * dse.c (dse_step1): When removing redundant stores make sure to adjust the earlier stores alias-set to match semantics of the removed one and its own. (dse_step6): Likewise. * g++.dg/torture/pr77745.C: Mark foo noinline to trigger latent bug in DSE. Index: gcc/dse.c =================================================================== --- gcc/dse.c (revision 257043) +++ gcc/dse.c (working copy) @@ -2725,6 +2725,19 @@ dse_step1 (void) "eliminated\n", INSN_UID (ptr->insn), INSN_UID (s_info->redundant_reason->insn)); + /* If the later store we delete could have changed the + dynamic type of the memory make sure the one we + preserve serves as a store for all loads that could + validly have accessed the one we delete. */ + store_info *r_info = s_info->redundant_reason->store_rec; + while (r_info) + { + if (r_info->is_set + && (MEM_ALIAS_SET (s_info->mem) + != MEM_ALIAS_SET (r_info->mem))) + set_mem_alias_set (r_info->mem, 0); + r_info = r_info->next; + } delete_dead_store_insn (ptr); } free_store_info (ptr); @@ -3512,6 +3525,19 @@ dse_step6 (void) "eliminated\n", INSN_UID (insn_info->insn), INSN_UID (rinsn)); + /* If the later store we delete could have changed the + dynamic type of the memory make sure the one we + preserve serves as a store for all loads that could + validly have accessed the one we delete. */ + store_info *r_info = s_info->redundant_reason->store_rec; + while (r_info) + { + if (r_info->is_set + && (MEM_ALIAS_SET (s_info->mem) + != MEM_ALIAS_SET (r_info->mem))) + set_mem_alias_set (r_info->mem, 0); + r_info = r_info->next; + } delete_dead_store_insn (insn_info); } } Index: gcc/testsuite/g++.dg/torture/pr77745.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr77745.C (revision 257043) +++ gcc/testsuite/g++.dg/torture/pr77745.C (working copy) @@ -2,7 +2,7 @@ inline void* operator new(__SIZE_TYPE__, void* __p) noexcept { return __p; } -long foo(char *c1, char *c2) +long __attribute__((noinline)) foo(char *c1, char *c2) { long *p1 = new (c1) long; *p1 = 100;