https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86554
--- Comment #7 from Richard Biener <rguenth at gcc dot gnu.org> --- So on trunk the remaining offender now is code hoisting. We still do value-numbering the same but correctly do _not_ use the values definition to simplify the comparison: Value numbering stmt = ret_13 = PHI <ret_11(3), ret_12(4)> Setting value number of ret_13 to ret_12 (changed) Making available beyond BB5 ret_13 for value ret_12 Value numbering stmt = printf ("ret is %d\n", ret_13); Setting value number of .MEM_6 to .MEM_6 (changed) Value numbering stmt = if (ret_13 <= 0) Recording on edge 5->6 ret_13 le_expr 0 == true Recording on edge 5->6 ret_13 gt_expr 0 == false marking outgoing edge 5 -> 6 executable marking outgoing edge 5 -> 7 executable for code-hoisting both computations are antic-in in their respective definition blocks and thus the value is hoisted choosing the computation based on the expressions available in that block (the non-conversion one since the unconverted unsigned expression isn't ANTIC_IN). Note that a possible mitigation is to dumb down VN, not making this kind of conversions value-number to the same value (but possibly only conversions from signed to unsigned). OTOH the value-numbering itself isn't the issue but rather how we compute ANTIC. That is, this looks like an inherent issue of GVN-PRE. We can, of course fix up inserts to use unsigned arithmetic but that has impact on code quality in the majority of cases where no such false equivalency is detected. Need to think about this some more.