https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85803
Bug ID: 85803 Summary: [6/7/8/9 Regression] DSE removes live global store Product: gcc Version: 8.1.0 Status: UNCONFIRMED Keywords: wrong-code Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: rguenth at gcc dot gnu.org Target Milestone: --- Due to an algorithmic defect GIMPLE DSE removes the global store to *p in the if (i == 42) condition. This is because it relies on the presence of virtual operands on _all_ use sites, including ones outside of the function. One might think the if (ref_may_alias_global_p (ref)) return DSE_STORE_LIVE; protects such cases but that only works if no alternate definition site is found. That is, for this bug to trigger we need to have sth like if (..) exit-of-function-w/o-VUSE; # _2 = VDEF <_1> GIMPLE_RESX is amongst the opcodes that (can?) exit the function but have no associated virtual operands. Testcase, fails at -O2 with GCC 5+ (didn't verify if with 4.9.4 the issue is just latent for whatever reason): #include <setjmp.h> #include <signal.h> #include <stdlib.h> extern void maybethrow(void*); int cond, *globp; static inline void __attribute__((always_inline)) inlinethrow(void *p) { *globp = 43; } int __attribute__((noinline,noclone)) foo (int *p, int i) { if (i) { if (i == 42) { *p = 42; int local __attribute__((cleanup(inlinethrow))); } *p = 0; } *p = 1; return i + 1; } jmp_buf buf; static void segv_handler(int seg) { longjmp (buf, 1); } int x; int main() { struct sigaction sa, origsa; sa.sa_handler = segv_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGSEGV, &sa, NULL); if (!setjmp (buf)) foo (&x, 42); if (x != 42) abort (); return 0; } I beleive the proper course of action is to make all function exiting GIMPLE ops have a VUSE (and adjust ref_maybe_used_by_stmt_p accordingly as it was done for GIMPLE_RETURN). If you remove the above check in DSE (which should be redundant) you'll see some more cleanup and EH tests fail.