The average fallback is restricted to unsigned types, but it also works for
signed types. Arithmetic right shifts round down, and the low-bit carry
adjusts the result in the same way.
Remove the unsigned restriction. Use target_supports_op_p rather than
optab_for_tree_code to check whether the fallback operations are available.
Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
Ok for trunk?
gcc/ChangeLog:
PR tree-optimization/89007
* tree-vect-patterns.cc (vect_recog_average_pattern): Allow signed
types in the fallback. Check whether the fallback operations are
supported.
gcc/testsuite/ChangeLog:
PR tree-optimization/89007
* gcc.target/i386/pr89007.c: New test.
---
gcc/testsuite/gcc.target/i386/pr89007.c | 20 ++++++++++++++++++++
gcc/tree-vect-patterns.cc | 24 ++++++++++++------------
2 files changed, 32 insertions(+), 12 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/i386/pr89007.c
diff --git a/gcc/testsuite/gcc.target/i386/pr89007.c
b/gcc/testsuite/gcc.target/i386/pr89007.c
new file mode 100644
index 00000000000..854fb54700a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr89007.c
@@ -0,0 +1,20 @@
+/* PR tree-optimization/89007 */
+/* { dg-do compile } */
+/* { dg-options "-O3 -mavx512bw -mavx512vl -mprefer-vector-width=512" } */
+
+void
+avg_floor (short *restrict d, short *restrict a, short *restrict b, int n)
+{
+ for (int i = 0; i < n; i++)
+ d[i] = (a[i] + b[i]) >> 1;
+}
+
+void
+avg_ceil (short *restrict d, short *restrict a, short *restrict b, int n)
+{
+ for (int i = 0; i < n; i++)
+ d[i] = (a[i] + b[i] + 1) >> 1;
+}
+
+/* { dg-final { scan-assembler "vpsraw\[ \t\]" } } */
+/* { dg-final { scan-assembler-not "vpsrad\[ \t\]" } } */
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 406f81b95c8..15046a1cea9 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -3581,17 +3581,15 @@ vect_recog_average_pattern (vec_info *vinfo,
if (!new_vectype)
return NULL;
- bool fallback_p = false;
-
- if (direct_internal_fn_supported_p (ifn, new_vectype, OPTIMIZE_FOR_SPEED))
- ;
- else if (TYPE_UNSIGNED (new_type)
- && optab_for_tree_code (RSHIFT_EXPR, new_vectype, optab_scalar)
- && optab_for_tree_code (PLUS_EXPR, new_vectype, optab_default)
- && optab_for_tree_code (BIT_IOR_EXPR, new_vectype, optab_default)
- && optab_for_tree_code (BIT_AND_EXPR, new_vectype, optab_default))
- fallback_p = true;
- else
+ bool fallback_p = !direct_internal_fn_supported_p (ifn, new_vectype,
+ OPTIMIZE_FOR_SPEED);
+ if (fallback_p
+ && (!target_supports_op_p (new_vectype, RSHIFT_EXPR, optab_scalar)
+ || !target_supports_op_p (new_vectype, PLUS_EXPR, optab_default)
+ || !target_supports_op_p (new_vectype, BIT_AND_EXPR, optab_default)
+ || (ifn == IFN_AVG_CEIL
+ && !target_supports_op_p (new_vectype, BIT_IOR_EXPR,
+ optab_default))))
return NULL;
/* The IR requires a valid vector type for the cast result, even though
@@ -3615,7 +3613,9 @@ vect_recog_average_pattern (vec_info *vinfo,
unmasked_carry = new_ops[0] and/or new_ops[1];
carry = unmasked_carry & 1;
new_var = sum_of_shifted + carry;
- */
+
+ For signed types, arithmetic shifts round down and the carry is one
+ when both operands are odd (or either operand for IFN_AVG_CEIL). */
tree one_cst = build_one_cst (new_type);
gassign *g;
--
2.34.1