https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37242
--- Comment #26 from Richard Biener <rguenth at gcc dot gnu.org> --- /* Match arithmetic done in a different type where we can easily substitute the result from some earlier sign-changed or widened operation. */ if (INTEGRAL_TYPE_P (type) && TREE_CODE (rhs1) == SSA_NAME /* We only handle sign-changes or zero-extension -> & mask. */ this is sign-extension... I think if the inner op has undefined overflow we can widen it(?). That fixes the new testcase. Index: gcc/tree-ssa-sccvn.c =================================================================== --- gcc/tree-ssa-sccvn.c (revision 274670) +++ gcc/tree-ssa-sccvn.c (working copy) @@ -4312,8 +4312,11 @@ visit_nary_op (tree lhs, gassign *stmt) operation. */ if (INTEGRAL_TYPE_P (type) && TREE_CODE (rhs1) == SSA_NAME - /* We only handle sign-changes or zero-extension -> & mask. */ - && ((TYPE_UNSIGNED (TREE_TYPE (rhs1)) + /* We only handle sign-changes, zero-extension -> & mask or + sign-extension if we know the inner operation doesn't + overflow. */ + && (((TYPE_UNSIGNED (TREE_TYPE (rhs1)) + || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (rhs1))) && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (rhs1))) || TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (rhs1)))) { @@ -4347,7 +4350,8 @@ visit_nary_op (tree lhs, gassign *stmt) { unsigned lhs_prec = TYPE_PRECISION (type); unsigned rhs_prec = TYPE_PRECISION (TREE_TYPE (rhs1)); - if (lhs_prec == rhs_prec) + if (lhs_prec == rhs_prec + || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (rhs1))) { gimple_match_op match_op (gimple_match_cond::UNCOND, NOP_EXPR, type, ops[0]); for the benchmark PRE inserts the this way redundant code: Found partial redundancy for expression {nop_expr,maxIdx_31} (0012) Inserted _72 = (long unsigned int) maxIdx_42; in predecessor 4 (0052) but late FRE can get rid of it again.