https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88280
--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> --- (In reply to Richard Biener from comment #1) > Confirmed. g and h end up like this before RTL expansion (initial folding > produces this): > > j_6 = i_4(D) & a_5(D); > _1 = i_4(D) != 0; > _2 = j_6 != 0; > _3 = _1 & _2; > _7 = (int) _3; > return _7; > > and for e we do not combine the i != 0 check. > > <bb 2> [local count: 1073741824]: > if (i_3(D) != 0) > goto <bb 3>; [50.00%] > else > goto <bb 4>; [50.00%] > > <bb 3> [local count: 536870913]: > _1 = i_3(D) & a_4(D); > _6 = _1 != 0; > _7 = (int) _6; > > <bb 4> [local count: 1073741824]: > # iftmp.0_2 = PHI <_7(3), i_3(D)(2)> > return iftmp.0_2; Yeah, with f we are just lucky that (i & a) != 0 test is in a different basic block and dominates the i != 0 test; EVRP then adds assertions from that (i & a) != 0 that i != 0 as well as a != 0 and optimizes the second redundant check out. For g and h we could in theory handle that through some match.pd pattern, but dunno if it wouldn't be way too much specialized. If we wanted to do something about e, it would need to be done in reassoc range handling, but again, not really sure how often it would trigger on real-world code.