The existing VEC_COND_EXPR min/max patterns require the comparison and result
constants to be equal so they do not recognize this canonicalized form.
Add patterns for the GE/LT forms produced from negative signed maximum
expressions and for the LE/GT forms produced from positive signed or unsigned
minimum expressions. Handle both normal and reversed conditional arms.
The off-by-one check is performed elementwise so the transform is not
restricted to uniform vector constants.

This also handles non-uniform vector constants such as:
X >= { -99, -98 } ? X : { -100, -99 }
which can be folded to:
MAX_EXPR <X, { -100, -99 }>
when each comparison element is exactly one greater than the corresponding
result element. Variable-length vector constants are handled when the two
constants have matching VECTOR_CST encodings.

gcc/ChangeLog:
        PR tree-optimization/98602
        * match.pd (vec_cond (cmp @0 VECTOR_CST@1) @0 VECTOR_CST@2):
        New simplification.
        (vec_cond (cmp @0 VECTOR_CST@1) VECTOR_CST@2 @0): Likewise.

gcc/testsuite/ChangeLog:
        PR tree-optimization/98602
        * g++.dg/tree-ssa/pr98602.C: New test.
        * g++.target/aarch64/sve/max_1.C: Remove fixed XFAILs.
        * g++.target/aarch64/sve/min_1.C: Likewise.

Signed-off-by: Naveen <[email protected]>
---
 gcc/match.pd                                 | 146 +++++++++++++++++++
 gcc/testsuite/g++.dg/tree-ssa/pr98602.C      |  37 +++++
 gcc/testsuite/g++.target/aarch64/sve/max_1.C |  10 +-
 gcc/testsuite/g++.target/aarch64/sve/min_1.C |  44 +++---
 4 files changed, 210 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr98602.C

diff --git a/gcc/match.pd b/gcc/match.pd
index 017b1362b7e..1795963b0c6 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6822,6 +6822,152 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && target_supports_op_p (type, MINMAX, optab_vector))
     (minmax @0 @1))))
 
+/* Comparison canonicalization changes X > C to X >= C + 1 for
+   negative C and X < C to X <= C - 1 for positive C.  */
+(for cmp (ge le)
+     minmax (max min)
+     MINMAX (MAX_EXPR MIN_EXPR)
+ (simplify
+  (vec_cond (cmp @0 VECTOR_CST@1) @0 VECTOR_CST@2)
+  (with
+   {
+     bool ok = true;
+
+     if (!known_eq (VECTOR_CST_NELTS (@1), VECTOR_CST_NELTS (@2)))
+       ok = false;
+     else
+       {
+        unsigned HOST_WIDE_INT nelts;
+        if (VECTOR_CST_NELTS (@1).is_constant (&nelts))
+          {
+            for (unsigned HOST_WIDE_INT i = 0; i < nelts; ++i)
+              {
+                tree cmp_cst = vector_cst_elt (@1, i);
+                tree res_cst = vector_cst_elt (@2, i);
+                if (TREE_CODE (cmp_cst) != INTEGER_CST
+                    || TREE_CODE (res_cst) != INTEGER_CST
+                    || tree_int_cst_sgn (res_cst)
+                       != (minmax == MAX_EXPR ? -1 : 1)
+                    || !wi::eq_p (wi::to_wide (cmp_cst),
+                                  wi::to_wide (res_cst)
+                                  + (minmax == MAX_EXPR ? 1 : -1)))
+                  {
+                    ok = false;
+                    break;
+                  }
+              }
+          }
+        else
+          {
+            /* For variable-length vectors, handle matching encodings and
+               check the encoded elements.  */
+            if (VECTOR_CST_LOG2_NPATTERNS (@1)
+                != VECTOR_CST_LOG2_NPATTERNS (@2)
+                || VECTOR_CST_NELTS_PER_PATTERN (@1)
+                   != VECTOR_CST_NELTS_PER_PATTERN (@2)
+                || vector_cst_encoded_nelts (@1)
+                   != vector_cst_encoded_nelts (@2))
+              ok = false;
+            else
+              {
+                unsigned int encoded_nelts = vector_cst_encoded_nelts (@1);
+                for (unsigned int i = 0; i < encoded_nelts; ++i)
+                  {
+                    tree cmp_cst = VECTOR_CST_ENCODED_ELT (@1, i);
+                    tree res_cst = VECTOR_CST_ENCODED_ELT (@2, i);
+                    if (TREE_CODE (cmp_cst) != INTEGER_CST
+                        || TREE_CODE (res_cst) != INTEGER_CST
+                        || tree_int_cst_sgn (res_cst)
+                           != (minmax == MAX_EXPR ? -1 : 1)
+                        || !wi::eq_p (wi::to_wide (cmp_cst),
+                                      wi::to_wide (res_cst)
+                                      + (minmax == MAX_EXPR ? 1 : -1)))
+                      {
+                        ok = false;
+                        break;
+                      }
+                  }
+              }
+          }
+       }
+   }
+   (if (VECTOR_INTEGER_TYPE_P (type)
+       && target_supports_op_p (type, MINMAX, optab_vector)
+       && ok)
+    (minmax @0 @2)))))
+
+(for cmp (lt gt)
+     minmax (max min)
+     MINMAX (MAX_EXPR MIN_EXPR)
+ (simplify
+  (vec_cond (cmp @0 VECTOR_CST@1) VECTOR_CST@2 @0)
+  (with
+   {
+     bool ok = true;
+
+     if (!known_eq (VECTOR_CST_NELTS (@1), VECTOR_CST_NELTS (@2)))
+       ok = false;
+     else
+       {
+        unsigned HOST_WIDE_INT nelts;
+        if (VECTOR_CST_NELTS (@1).is_constant (&nelts))
+          {
+            for (unsigned HOST_WIDE_INT i = 0; i < nelts; ++i)
+              {
+                tree cmp_cst = vector_cst_elt (@1, i);
+                tree res_cst = vector_cst_elt (@2, i);
+                if (TREE_CODE (cmp_cst) != INTEGER_CST
+                    || TREE_CODE (res_cst) != INTEGER_CST
+                    || tree_int_cst_sgn (res_cst)
+                       != (minmax == MAX_EXPR ? -1 : 1)
+                    || !wi::eq_p (wi::to_wide (cmp_cst),
+                                  wi::to_wide (res_cst)
+                                  + (minmax == MAX_EXPR ? 1 : -1)))
+                  {
+                    ok = false;
+                    break;
+                  }
+              }
+          }
+        else
+          {
+            /* For variable-length vectors, handle matching encodings and
+               check the encoded elements.  */
+            if (VECTOR_CST_LOG2_NPATTERNS (@1)
+                != VECTOR_CST_LOG2_NPATTERNS (@2)
+                || VECTOR_CST_NELTS_PER_PATTERN (@1)
+                   != VECTOR_CST_NELTS_PER_PATTERN (@2)
+                || vector_cst_encoded_nelts (@1)
+                   != vector_cst_encoded_nelts (@2))
+              ok = false;
+            else
+              {
+                unsigned int encoded_nelts = vector_cst_encoded_nelts (@1);
+                for (unsigned int i = 0; i < encoded_nelts; ++i)
+                  {
+                    tree cmp_cst = VECTOR_CST_ENCODED_ELT (@1, i);
+                    tree res_cst = VECTOR_CST_ENCODED_ELT (@2, i);
+                    if (TREE_CODE (cmp_cst) != INTEGER_CST
+                        || TREE_CODE (res_cst) != INTEGER_CST
+                        || tree_int_cst_sgn (res_cst)
+                           != (minmax == MAX_EXPR ? -1 : 1)
+                        || !wi::eq_p (wi::to_wide (cmp_cst),
+                                      wi::to_wide (res_cst)
+                                      + (minmax == MAX_EXPR ? 1 : -1)))
+                      {
+                        ok = false;
+                        break;
+                      }
+                  }
+              }
+          }
+       }
+   }
+   (if (VECTOR_INTEGER_TYPE_P (type)
+       && target_supports_op_p (type, MINMAX, optab_vector)
+       && ok)
+    (minmax @0 @2)))))
+
 /* Try to optimize x < 0 ? -1 : 0 into (signed) x >> 31
    and x < 0 ? 1 : 0 into (unsigned) x >> 31.  */
 (simplify
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr98602.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr98602.C
new file mode 100644
index 00000000000..6a4a421747a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr98602.C
@@ -0,0 +1,37 @@
+/* { dg-do compile { target aarch64*-*-* } } */
+/* { dg-options "-O1 -fdump-tree-forwprop1-raw -Wno-psabi" } */
+
+typedef int v4si __attribute__ ((vector_size (16)));
+typedef unsigned int v4ui __attribute__ ((vector_size (16)));
+
+v4si
+smax_nonuniform (v4si x)
+{
+  return x >= (v4si) { -99, -98, -97, -96 }
+        ? x : (v4si) { -100, -99, -98, -97 };
+}
+
+v4si
+smax_nonuniform_rev (v4si x)
+{
+  return x < (v4si) { -99, -98, -97, -96 }
+        ? (v4si) { -100, -99, -98, -97 } : x;
+}
+
+v4si
+smin_nonuniform (v4si x)
+{
+  return x <= (v4si) { 99, 100, 101, 102 }
+        ? x : (v4si) { 100, 101, 102, 103 };
+}
+
+v4ui
+umin_nonuniform_rev (v4ui x)
+{
+  return x > (v4ui) { 1, 2, 3, 4 }
+        ? (v4ui) { 2, 3, 4, 5 } : x;
+}
+
+/* { dg-final { scan-tree-dump-times "max_expr, " 2 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times "min_expr, " 2 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not "vec_cond_expr, " "forwprop1" } } */
diff --git a/gcc/testsuite/g++.target/aarch64/sve/max_1.C 
b/gcc/testsuite/g++.target/aarch64/sve/max_1.C
index caf9d7cd9bb..6328d5a1b38 100644
--- a/gcc/testsuite/g++.target/aarch64/sve/max_1.C
+++ b/gcc/testsuite/g++.target/aarch64/sve/max_1.C
@@ -39,11 +39,11 @@ TEST_TYPE (uint32_t, 128, 7, 255)
 /* { dg-final { scan-assembler-times {\tumax\tz[0-9]+\.h, p[0-7]/m, 
z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
 /* { dg-final { scan-assembler-times {\tumax\tz[0-9]+\.s, p[0-7]/m, 
z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
 
-/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #-100\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #-110\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #-120\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.h, z[0-9]+\.h, #-128\n} 
2 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.s, z[0-9]+\.s, #-128\n} 
1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #-100\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #-110\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #-120\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.h, z[0-9]+\.h, #-128\n} 
2 } } */
+/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.s, z[0-9]+\.s, #-128\n} 
1 } } */
 
 /* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.b, z[0-9]+\.b, #50\n} 3 
} } */
 /* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.h, z[0-9]+\.h, #50\n} 2 
} } */
diff --git a/gcc/testsuite/g++.target/aarch64/sve/min_1.C 
b/gcc/testsuite/g++.target/aarch64/sve/min_1.C
index 9c84690cd1b..172fa6a9da5 100644
--- a/gcc/testsuite/g++.target/aarch64/sve/min_1.C
+++ b/gcc/testsuite/g++.target/aarch64/sve/min_1.C
@@ -45,29 +45,29 @@ TEST_TYPE (uint32_t, 128, 7, 255)
 /* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h, #-128\n} 
2 } } */
 /* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s, #-128\n} 
1 } } */
 
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #50\n} 3 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h, #50\n} 2 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s, #50\n} 1 
{ xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #50\n} 3 
} } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h, #50\n} 2 
} } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s, #50\n} 1 
} } */
 
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #100\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #110\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #120\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h, #127\n} 
2 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s, #127\n} 
1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #100\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #110\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.b, z[0-9]+\.b, #120\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.h, z[0-9]+\.h, #127\n} 
2 } } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, z[0-9]+\.s, #127\n} 
1 } } */
 
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #2\n} 1 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #3\n} 1 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #4\n} 1 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #5\n} 1 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #6\n} 1 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #7\n} 1 
{ xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #2\n} 1 
} } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #3\n} 1 
} } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #4\n} 1 
} } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #5\n} 1 
} } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #6\n} 1 
} } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #7\n} 1 
} } */
 
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #50\n} 3 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #50\n} 2 
{ xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #50\n} 1 
{ xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #50\n} 3 
} } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #50\n} 2 
} } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #50\n} 1 
} } */
 
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #250\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #251\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #253\n} 
1 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #255\n} 
2 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #255\n} 
1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #250\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #251\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.b, z[0-9]+\.b, #253\n} 
1 } } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.h, z[0-9]+\.h, #255\n} 
2 } } */
+/* { dg-final { scan-assembler-times {\tumin\tz[0-9]+\.s, z[0-9]+\.s, #255\n} 
1 } } */
-- 
2.34.1

Reply via email to