(plus:c (mult:c (div @0 @1) @1) (mod @0 @1))
@0))
+/* x / y * y == x -> x % y == 0. */
+(simplify
+ (eq:c (mult:c (trunc_div:s @0 @1) @1) @0)
+ (if (TREE_CODE (TREE_TYPE (@0)) != COMPLEX_TYPE)
+ (eq (trunc_mod @0 @1) { build_zero_cst (TREE_TYPE (@0)); })))
+
/* ((X /[ex] A) +- B) * A --> X +- A * B. */
(for op (plus minus)
(simplify
--- /dev/null
+/* PR tree-optimization/104992 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#define vector __attribute__((vector_size(4*sizeof(int))))
+
+/* Form from PR. */
+__attribute__((noipa)) unsigned foo(unsigned x, unsigned y)
+{
+ return x / y * y == x;
+}
+
+__attribute__((noipa)) unsigned bar(unsigned x, unsigned y) {
+ return x == x / y * y;
+}
+
+/* Signed test case. */
+__attribute__((noipa)) unsigned baz (int x, int y) {
+ return x / y * y == x;
+}
+
+/* Changed order. */
+__attribute__((noipa)) unsigned qux (unsigned x, unsigned y) {
+ return y * (x / y) == x;
+}
+
+/* Test for forward propogation. */
+__attribute__((noipa)) unsigned corge(unsigned x, unsigned y) {
+ int z = x / y;
+ int q = z * y;
+ return q == x;
+}
+
+/* Test vector case. */
+__attribute__((noipa)) vector int thud(vector int x, vector int y) {
+ return x / y * y == x;
+}
+
+/* Complex type should not simplify because mod is different. */
+__attribute__((noipa)) int goo(_Complex int x, _Complex int y)
+{
+ _Complex int z = x / y;
+ _Complex int q = z * y;
+ return q == x;
+}
+
+/* Wrong order. */
+__attribute__((noipa)) unsigned fred (unsigned x, unsigned y) {
+ return y * x / y == x;
+}
+
+/* Wrong pattern. */
+__attribute__((noipa)) unsigned waldo (unsigned x, unsigned y, unsigned z) {
+ return x / y * z == x;
+}
+
+/* { dg-final {scan-tree-dump-times " % " 9 "optimized" } } */