zerop
initializer_each_zero_or_onep
CONSTANT_CLASS_P
+ poly_int_tree_p
tree_expr_nonnegative_p
tree_expr_nonzero_p
integer_valued_real_p
(mult (convert1? (exact_div @0 @@1)) (convert2? @1))
(convert @0))
+/* (X /[ex] C1) * (C1 * C2) -> X * C2. */
+(simplify
+ (mult (convert? (exact_div @0 INTEGER_CST@1)) poly_int_tree_p@2)
+ (with { poly_widest_int factor; }
+ (if (multiple_p (wi::to_poly_widest (@2), wi::to_widest (@1), &factor))
+ (mult (convert @0) { wide_int_to_tree (type, factor); }))))
+
/* Simplify (A / B) * B + (A % B) -> A. */
(for div (trunc_div ceil_div floor_div round_div)
mod (trunc_mod ceil_mod floor_mod round_mod)
--- /dev/null
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+#define TEST_CMP(FN, DIV, MUL) \
+ int \
+ FN (int x) \
+ { \
+ if (x & 7) \
+ __builtin_unreachable (); \
+ x /= DIV; \
+ return x * MUL; \
+ }
+
+TEST_CMP (f1, 2, 6)
+TEST_CMP (f2, 2, 10)
+TEST_CMP (f3, 4, 80)
+TEST_CMP (f4, 8, 200)
+
+/* { dg-final { scan-tree-dump-not {<[a-z]*_div_expr, } "optimized" } } */
+/* { dg-final { scan-tree-dump-not {<rshift_expr, } "optimized" } } */
+/* { dg-final { scan-tree-dump {<mult_expr, [^,]*, [^,]*, 3,} "optimized" } } */
+/* { dg-final { scan-tree-dump {<mult_expr, [^,]*, [^,]*, 5,} "optimized" } } */
+/* { dg-final { scan-tree-dump {<mult_expr, [^,]*, [^,]*, 20,} "optimized" } } */
+/* { dg-final { scan-tree-dump {<mult_expr, [^,]*, [^,]*, 25,} "optimized" } } */
--- /dev/null
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+#define TEST_CMP(FN, DIV, MUL) \
+ int \
+ FN (int x) \
+ { \
+ if (x & 7) \
+ __builtin_unreachable (); \
+ x /= DIV; \
+ return x * MUL; \
+ }
+
+TEST_CMP (f1, 2, 1)
+TEST_CMP (f2, 2, 5)
+TEST_CMP (f3, 4, 10)
+TEST_CMP (f4, 8, 100)
+TEST_CMP (f5, 16, 32)
+
+/* { dg-final { scan-tree-dump-times {<[a-z]*_div_expr, } 5 "optimized" } } */
--- /dev/null
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+#define TEST_CMP(FN, TYPE1, DIV, TYPE2, MUL) \
+ TYPE2 \
+ FN (TYPE1 x) \
+ { \
+ if (x & 7) \
+ __builtin_unreachable (); \
+ x /= (TYPE1) (DIV); \
+ return (TYPE2) x * (TYPE2) (MUL); \
+ }
+
+TEST_CMP (f1, int, 2, long, (~0UL >> 1) & -2)
+TEST_CMP (f2, int, 4, unsigned long, -8)
+TEST_CMP (f3, int, 8, unsigned int, -24)
+TEST_CMP (f4, long, 2, int, (~0U >> 1) & -2)
+TEST_CMP (f5, long, 4, unsigned int, 100)
+TEST_CMP (f6, long, 8, unsigned long, 200)
+
+/* { dg-final { scan-tree-dump-not {<[a-z]*_div_expr, } "optimized" } } */
+/* { dg-final { scan-tree-dump-not {<rshift_expr, } "optimized" } } */
--- /dev/null
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+int
+f1 (int x)
+{
+ if (x & 15)
+ __builtin_unreachable ();
+ x /= 2;
+ x = (unsigned short) x * 4;
+ return x;
+}
+
+
+/* { dg-final { scan-tree-dump {<exact_div_expr, } "optimized" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_sve.h>
+
+/*
+** f1:
+** cntd x([0-9]+)
+** mul w0, (w0, w\1|w\1, w0)
+** ret
+*/
+int
+f1 (int x)
+{
+ if (x & 1)
+ __builtin_unreachable ();
+ x /= 2;
+ return x * svcntw();
+}
+
+/*
+** f2:
+** cntd x([0-9]+)
+** mul w0, (w0, w\1|w\1, w0)
+** ret
+*/
+int
+f2 (int x)
+{
+ if (x & 3)
+ __builtin_unreachable ();
+ x /= 4;
+ return x * svcnth();
+}
+
+/*
+** f3:
+** cntd x([0-9]+)
+** mul w0, (w0, w\1|w\1, w0)
+** ret
+*/
+int
+f3 (int x)
+{
+ if (x & 7)
+ __builtin_unreachable ();
+ x /= 8;
+ return x * svcntb();
+}
+
+/*
+** f4:
+** cntw x([0-9]+)
+** mul w0, (w0, w\1|w\1, w0)
+** ret
+*/
+int
+f4 (int x)
+{
+ if (x & 1)
+ __builtin_unreachable ();
+ x /= 2;
+ return x * svcnth();
+}
+
+/*
+** f5:
+** cntw x([0-9]+)
+** mul w0, (w0, w\1|w\1, w0)
+** ret
+*/
+int
+f5 (int x)
+{
+ if (x & 3)
+ __builtin_unreachable ();
+ x /= 4;
+ return x * svcntb();
+}
+
+/*
+** f6:
+** cnth x([0-9]+)
+** mul w0, (w0, w\1|w\1, w0)
+** ret
+*/
+int
+f6 (int x)
+{
+ if (x & 1)
+ __builtin_unreachable ();
+ x /= 2;
+ return x * svcntb();
+}
+
+/*
+** f7:
+** cntb x([0-9]+)
+** mul w0, (w0, w\1|w\1, w0)
+** ret
+*/
+int
+f7 (int x)
+{
+ if (x & 15)
+ __builtin_unreachable ();
+ x /= 16;
+ return x * svcntb() * 16;
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+int
+f1 (int x)
+{
+ x /= 2;
+ return x * svcntw();
+}
+
+int
+f2 (int x)
+{
+ x /= 4;
+ return x * svcnth();
+}
+
+int
+f3 (int x)
+{
+ x /= 8;
+ return x * svcntb();
+}
+
+int
+f4 (int x)
+{
+ x /= 2;
+ return x * svcnth();
+}
+
+int
+f5 (int x)
+{
+ x /= 4;
+ return x * svcntb();
+}
+
+int
+f6 (int x)
+{
+ x /= 2;
+ return x * svcntb();
+}
+
+int
+f7 (int x)
+{
+ x /= 16;
+ return x * svcntb() * 16;
+}
+
+/* { dg-final { scan-assembler-times {\tasr\t} 7 } } */