From: juewang <[email protected]>

Use a single-use unpromoted input when MAX_EXPR and SAT_TRUNC are
supported for the narrower type, avoiding a redundant widen-and-narrow
sequence.

Changes since v1:
 v1: Add vect_sat_trunc_clip_input_vectype to check target support.
     Use the appropriate gimple_build_assign overload for MAX_EXPR.

gcc/ChangeLog:

        * tree-vect-patterns.cc (vect_sat_trunc_clip_input_vectype): New.
        (vect_recog_sat_trunc_pattern): Look through promotions and check
        target support for MAX_EXPR.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rvv/autovec/pr120378-2.c: Dump optimized GIMPLE.
        * gcc.target/riscv/rvv/autovec/pr120378-3.c: Likewise.  Disable the
        vector cost model.
        * gcc.target/riscv/rvv/autovec/pr120378-4.c: Likewise.
        * gcc.target/riscv/rvv/autovec/sat-trunc-promote-1.c: New test.
        * gcc.target/riscv/rvv/autovec/sat-trunc-promote-run-1.c: New test.
---
 .../gcc.target/riscv/rvv/autovec/pr120378-2.c |  2 +-
 .../gcc.target/riscv/rvv/autovec/pr120378-3.c |  2 +-
 .../gcc.target/riscv/rvv/autovec/pr120378-4.c |  2 +-
 .../riscv/rvv/autovec/sat-trunc-promote-1.c   | 25 ++++++
 .../rvv/autovec/sat-trunc-promote-run-1.c     | 45 ++++++++++
 gcc/tree-vect-patterns.cc                     | 83 +++++++++++++++----
 6 files changed, 140 insertions(+), 19 deletions(-)
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-1.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-run-1.c

diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
index 9a880e0f67b..2208e954242 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fdump-tree-optimized" } */
 
 #include <stdint.h>
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
index d6b2ddd3f8d..a71f8bfa19a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-3.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-vect-cost-model 
-fdump-tree-optimized" } */
 
 #include <stdint.h>
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
index 4657e52f883..bc9a55e8b07 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr120378-4.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv64gcv -mabi=lp64d -O3" } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -fno-vect-cost-model 
-fdump-tree-optimized" } */
 
 #include <stdint.h>
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-1.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-1.c
new file mode 100644
index 00000000000..b0f553a692d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-1.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -mrvv-max-lmul=m1 
-fno-vect-cost-model -fdump-tree-optimized" } */
+
+#include <stdint-gcc.h>
+
+static inline uint8_t
+clip_uint8 (int x)
+{
+  return x & ~255 ? (-x) >> 31 : x;
+}
+
+__attribute__ ((noipa)) void
+hpel_clip (uint8_t *__restrict dst, const uint8_t *__restrict src, int n)
+{
+  for (int i = 0; i < n; ++i)
+    {
+      int value = (src[i - 2] + src[i + 3]
+                  - 5 * (src[i - 1] + src[i + 2])
+                  + 20 * (src[i] + src[i + 1]));
+      dst[i] = clip_uint8 ((value + 16) >> 5);
+    }
+}
+
+/* { dg-final { scan-tree-dump-times {\.SAT_TRUNC } 1 "optimized" } } */
+/* { dg-final { scan-assembler-times {\tvnclipu\.wi} 1 } } */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-run-1.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-run-1.c
new file mode 100644
index 00000000000..6249defff38
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat-trunc-promote-run-1.c
@@ -0,0 +1,45 @@
+/* { dg-do run { target { riscv_v && rv64 } } } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -mrvv-max-lmul=m1 
-fno-vect-cost-model" } */
+
+#include <stdint-gcc.h>
+
+#define N 128
+
+static inline uint8_t
+clip_uint8 (int x)
+{
+  return x & ~255 ? (-x) >> 31 : x;
+}
+
+__attribute__ ((noipa)) static void
+clip_loop (uint8_t *__restrict dst, const int16_t *__restrict src, int n)
+{
+  for (int i = 0; i < n; ++i)
+    {
+      int x = (src[i] >> 8) * 256 + (src[i] & 255);
+      dst[i] = clip_uint8 (x);
+    }
+}
+
+int
+main (void)
+{
+  static const int16_t values[] = {
+    INT16_MIN, -1, 0, 255, 256, INT16_MAX
+  };
+  static const uint8_t expected[] = { 0, 0, 0, 255, 255, 255 };
+  int16_t input[N];
+  uint8_t output[N];
+
+  for (int i = 0; i < N; ++i)
+    input[i] = values[i % 6];
+
+  clip_loop (output, input, N);
+
+#pragma GCC novector
+  for (int i = 0; i < N; ++i)
+    if (output[i] != expected[i % 6])
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 406f81b95c8..f87a221cf65 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -4815,6 +4815,24 @@ vect_recog_sat_sub_pattern (vec_info *vinfo, 
stmt_vec_info stmt_vinfo,
   return NULL;
 }
 
+/* Return the vector type for ITYPE if the target supports the MAX_EXPR
+   and SAT_TRUNC sequence.  */
+
+static tree
+vect_sat_trunc_clip_input_vectype (vec_info *vinfo, tree v_otype,
+                                  tree itype)
+{
+  tree v_itype;
+  if (!vect_supportable_direct_optab_p
+       (vinfo, itype, MAX_EXPR, itype, &v_itype)
+      || !direct_internal_fn_supported_p
+          (IFN_SAT_TRUNC, tree_pair (v_otype, v_itype),
+           OPTIMIZE_FOR_BOTH))
+    return NULL_TREE;
+
+  return v_itype;
+}
+
 /*
  * Try to detect saturation truncation pattern (SAT_TRUNC), aka below gimple:
  *   overflow_5 = x_4(D) > 4294967295;
@@ -4843,31 +4861,64 @@ vect_recog_sat_trunc_pattern (vec_info *vinfo, 
stmt_vec_info stmt_vinfo,
   if ((gimple_unsigned_integer_narrow_clip (lhs, ops, NULL))
        && type_has_mode_precision_p (otype))
     {
-      tree itype = TREE_TYPE (ops[0]);
-      tree v_itype = get_vectype_for_scalar_type (vinfo, itype);
+      tree input = ops[0];
+      tree itype = TREE_TYPE (input);
       tree v_otype = get_vectype_for_scalar_type (vinfo, otype);
       internal_fn fn = IFN_SAT_TRUNC;
+      tree v_itype = NULL_TREE;
 
-      if (v_itype != NULL_TREE && v_otype != NULL_TREE
-       && direct_internal_fn_supported_p (fn, tree_pair (v_otype, v_itype),
-                                          OPTIMIZE_FOR_BOTH))
+      if (v_otype != NULL_TREE)
        {
-         tree temp = vect_recog_temp_ssa_var (itype, NULL);
-         gimple * max_stmt = gimple_build_assign (temp, build2 (MAX_EXPR, 
itype, build_zero_cst(itype), ops[0]));
-         append_pattern_def_seq (vinfo, stmt_vinfo, max_stmt, v_itype);
+         /* Avoid widening an input only to narrow it again.  A signed
+            promotion does not affect MAX (X, 0), so use the unpromoted
+            value when the target can narrow it directly to the output
+            type.  */
+         vect_unpromoted_value unprom;
+         bool single_use_p = true;
+         if (vect_look_through_possible_promotion (vinfo, input, &unprom,
+                                                     &single_use_p)
+             && single_use_p
+             && INTEGRAL_TYPE_P (unprom.type)
+             && TYPE_SIGN (unprom.type) == TYPE_SIGN (itype)
+             && type_has_mode_precision_p (unprom.type)
+             && TYPE_PRECISION (otype) < TYPE_PRECISION (unprom.type)
+             && TYPE_PRECISION (unprom.type) < TYPE_PRECISION (itype))
+           {
+             tree v_unprom_type
+               = vect_sat_trunc_clip_input_vectype (vinfo, v_otype,
+                                                      unprom.type);
+             if (v_unprom_type != NULL_TREE)
+               {
+                 input = unprom.op;
+                 itype = unprom.type;
+                 v_itype = v_unprom_type;
+               }
+           }
 
-         gcall *call = gimple_build_call_internal (fn, 1, temp);
-         tree out_ssa = vect_recog_temp_ssa_var (otype, NULL);
+         if (v_itype == NULL_TREE)
+           v_itype
+             = vect_sat_trunc_clip_input_vectype (vinfo, v_otype, itype);
 
-         gimple_call_set_lhs (call, out_ssa);
-         gimple_call_set_nothrow (call, /* nothrow_p */ false);
-         gimple_set_location (call, gimple_location (last_stmt));
+         if (v_itype != NULL_TREE)
+           {
+             tree temp = vect_recog_temp_ssa_var (itype, NULL);
+             gimple *max_stmt
+               = gimple_build_assign (temp, MAX_EXPR,
+                                      build_zero_cst (itype), input);
+             append_pattern_def_seq (vinfo, stmt_vinfo, max_stmt, v_itype);
 
-         *type_out = v_otype;
+             gcall *call = gimple_build_call_internal (fn, 1, temp);
+             tree out_ssa = vect_recog_temp_ssa_var (otype, NULL);
 
-         return call;
-       }
+             gimple_call_set_lhs (call, out_ssa);
+             gimple_call_set_nothrow (call, false);
+             gimple_set_location (call, gimple_location (last_stmt));
 
+             *type_out = v_otype;
+
+             return call;
+           }
+       }
     }
 
   if ((gimple_unsigned_integer_sat_trunc (lhs, ops, NULL)
-- 
2.34.1

Reply via email to