https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97378
--- Comment #2 from Aldy Hernandez <aldyh at gcc dot gnu.org> --- (In reply to David Binderman from comment #1) > I have similar for the following C code: > > int a, b, c; > void d() { > e : { > long f; > long *g = &f; > if ((a != 0) - (b = 0)) > ; > else > a &= (*g %= a *= c) >= (*g || f); > goto e; > } > } > > Compiler flag -O2. For the C snippet above, we are queuing the assignment to _7 for removal: Folding statement: _7 = a.0_1 * c.3_6; EVRP:hybrid: RVRP found singleton 0 Queued stmt for removal. Folds to: 0 Yet there is still one use of _7 dangling around at the end of evrp: _17 = _7 & _29; It looks like substitute_and_fold_engine::replace_uses_in() is not propagating into the above statement because ranger can't find the range of _7 at FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE) { tree tuse = USE_FROM_PTR (use); tree val = value_of_expr (tuse, stmt); => if (val == tuse || val == NULL_TREE) continue; (gdb) dd stmt _17 = _7 & _29; (gdb) dd tuse _7 (gdb) dd val <nil> And the reason why value_of_expr() returns NULL is because the range for _7 here is actually UNDEFINED (i.e. unreachable). It looks like we can never make it to BB 5 (where _17 = _7 & _29 lives). Because BB5 is predicated by a division by zero: <bb 3> : c.3_6 = c; _7 = a.0_1 * c.3_6; a = 0; _9 = (long int) _7; _10 = f_33(D) % 0; if (_10 != 0) goto <bb 5>; [INV] else goto <bb 4>; [INV] <bb 5> : ... _17 = _7 & _29; The division by zero was product of various transformations. Basically we know that a.0_1 is 0, so we _7 is 0, which means _9 is also 0, which means that final conditional can't happen: <bb 3> : c.3_6 = c; _7 = a.0_1 * c.3_6; a = _7; _9 = (long int) _7; _10 = f_33(D) % _9; if (_10 != 0) Andrew can take it from here, but it looks like the substitute_and_fold engine must be able to remove *ALL* references to an LHS whose definition was folded away, even if said references appear in unreachable code.