Hi! On top of the previously posted patch, this simplifies say (x * 16) / (x * 4) into 4. Unlike the previous pattern, this is something we didn't fold previously on GENERIC, so I think it shouldn't be all wrapped with #if GIMPLE. The question whether there should be fold_overflow_warning for the TYPE_OVERFLOW_UNDEFINED case remains.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk (with or without fold_overflow_warning)? 2023-12-13 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/112994 * match.pd ((t * u) / (t * v) -> (u / v)): New simplification. * gcc.dg/tree-ssa/pr112994-2.c: New test. --- gcc/match.pd.jj 2023-12-13 18:43:51.277839661 +0100 +++ gcc/match.pd 2023-12-13 18:43:45.891913683 +0100 @@ -962,6 +960,23 @@ (define_operator_list SYNC_FETCH_AND_AND && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1)) (mult @0 (div! @1 @2)))) #endif + ))) + /* Simplify (t * u) / (t * v) -> (u / v) if u is multiple of v. */ + (simplify + (div (mult @0 INTEGER_CST@1) (mult @0 INTEGER_CST@2)) + (if (INTEGRAL_TYPE_P (type) + && wi::multiple_of_p (wi::to_widest (@1), wi::to_widest (@2), SIGNED)) + (if (TYPE_OVERFLOW_UNDEFINED (type) && !TYPE_OVERFLOW_SANITIZED (type)) + (div @1 @2) +#if GIMPLE + (with {value_range vr0, vr1, vr2;} + (if (get_range_query (cfun)->range_of_expr (vr0, @0) + && get_range_query (cfun)->range_of_expr (vr1, @1) + && get_range_query (cfun)->range_of_expr (vr2, @2) + && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1) + && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr2)) + (div @1 @2))) +#endif )))) #if GIMPLE --- gcc/testsuite/gcc.dg/tree-ssa/pr112994-2.c.jj 2023-12-13 19:07:20.882475735 +0100 +++ gcc/testsuite/gcc.dg/tree-ssa/pr112994-2.c 2023-12-13 19:07:02.597726855 +0100 @@ -0,0 +1,15 @@ +/* PR tree-optimization/112994 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 2;" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "return 7;" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "return -7;" 2 "optimized" } } */ + +int f1 (int x) { return (x * 4) / (x * 2); } +int f2 (int x) { return (x * 56) / (x * 8); } +int f3 (int x) { return (x * 56) / (x * -8); } +int f4 (int x) { int y = x * 4; return y / (x * 2); } +int f5 (int x) { int y = x * 56; return y / (x * 8); } +int f6 (int x) { int y = x * 56; return y / (x * -8); } +unsigned f7 (unsigned x) { if (x > ~0U / 4) __builtin_unreachable (); unsigned y = x * 4; return y / (x * 2); } +unsigned f8 (unsigned x) { if (x > ~0U / 56) __builtin_unreachable (); unsigned y = x * 56; return y / (x * 8); } Jakub