From: Kyrylo Tkachov <[email protected]>
The unsigned_integer_narrow_clip pattern assumes that its comparison
is unsigned and its right shift is signed. nop_convert? does not
require an unsigned conversion. The :s suffix marks a single-use
value rather than a signed type.
A signed comparison can preserve negative inputs. An unsigned right
shift produces zero or one instead of the all-ones clip value. Capture
both expressions and check their result types before applying the
transform.
The tests cover each rejected form. The unsigned-shift test constrains
the input range so that the existing INT_MIN guard does not reject it
first.
Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill
gcc/ChangeLog:
* match-sat-alu.pd (unsigned_integer_narrow_clip): Require an
unsigned comparison and a signed right shift.
gcc/testsuite/ChangeLog:
* gcc.dg/vect/pr127166-2.c: New test.
* gcc.target/riscv/rvv/autovec/pr127166.c: New test.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
gcc/match-sat-alu.pd | 13 +++--
gcc/testsuite/gcc.dg/vect/pr127166-2.c | 44 +++++++++++++++
.../gcc.target/riscv/rvv/autovec/pr127166.c | 53 +++++++++++++++++++
3 files changed, 105 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/vect/pr127166-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c
diff --git a/gcc/match-sat-alu.pd b/gcc/match-sat-alu.pd
index 7bbe2bbb26e..22855726d90 100644
--- a/gcc/match-sat-alu.pd
+++ b/gcc/match-sat-alu.pd
@@ -207,16 +207,19 @@ along with GCC; see the file COPYING3. If not see
/* SAT_U_TRUNC<NT>(MAX (0, X)) =
(UT)X & ~(NT)(-1) ? (-X) >> TYPE_PRECISION(X) - 1 : X
- The gimple representation uses X > ~(NT)(-1) instead of
- using & so match on gt instead of bit_and.
+ The gimple representation uses an unsigned X > ~(NT)(-1) instead of
+ using & so match on gt instead of bit_and. The right shift must be
+ signed so that it produces -1 for values above NT_MAX.
The two sides only agree when X is not the minimum of its type. At
that value the negation is its own inverse, so the shift yields -1
and the expression gives NT_MAX where MAX (0, X) gives 0. */
- (convert (cond^ (gt (nop_convert? @0) INTEGER_CST@1)
- (rshift:s (nop_convert? (negate (nop_convert? @0))) INTEGER_CST@2)
+ (convert (cond^ (gt (nop_convert?@3 @0) INTEGER_CST@1)
+ (rshift:s@4 (nop_convert? (negate (nop_convert? @0))) INTEGER_CST@2)
@0))
- (if (! TYPE_UNSIGNED (TREE_TYPE (@0)))
+ (if (! TYPE_UNSIGNED (TREE_TYPE (@0))
+ && TYPE_UNSIGNED (TREE_TYPE (@3))
+ && ! TYPE_UNSIGNED (TREE_TYPE (@4)))
(with
{
unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0));
diff --git a/gcc/testsuite/gcc.dg/vect/pr127166-2.c
b/gcc/testsuite/gcc.dg/vect/pr127166-2.c
new file mode 100644
index 00000000000..9e48c44d06e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr127166-2.c
@@ -0,0 +1,44 @@
+/* PR tree-optimization/127166 */
+/* { dg-require-effective-target int32 } */
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+
+#define N 64
+
+__attribute__ ((noipa)) void
+clip (unsigned short *__restrict out, const int *__restrict in, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ int x = in[i] & __INT_MAX__;
+ out[i] = ((unsigned int) x > 65535u
+ ? (unsigned int) (-x) >> 31 : x);
+ }
+}
+
+int
+main (void)
+{
+ int in[N];
+ unsigned short out[N];
+
+ check_vect ();
+
+ for (int i = 0; i < N; ++i)
+ in[i] = (i & 1) ? -1 : 70000 + i;
+
+ clip (out, in, N);
+
+#pragma GCC novector
+ for (int i = 0; i < N; ++i)
+ {
+ if (out[i] != 1)
+ abort ();
+ }
+
+ return 0;
+}
+
+/* The unsigned right shift does not produce the all-ones clip value. */
+/* { dg-final { scan-tree-dump-not "\\.SAT_TRUNC" "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c
new file mode 100644
index 00000000000..30a43ad64ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c
@@ -0,0 +1,53 @@
+/* PR tree-optimization/127166 */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O2 -fgimple" } */
+/* { dg-additional-options "-fdump-tree-vect-details" } */
+
+void __GIMPLE (ssa, startwith ("fix_loops"))
+clip_signed_compare (unsigned short *out, const int *in)
+{
+ int i;
+ int raw;
+ int x;
+ int neg;
+ int shifted;
+ int selected;
+ unsigned short narrowed;
+ _Bool cmp;
+ const int *pin;
+ const int *next_pin;
+ unsigned short *pout;
+ unsigned short *next_pout;
+
+__BB(2):
+ goto __BB3;
+
+__BB(3):
+ i_1 = __PHI (__BB2: 0, __BB4: i_2);
+ pin_3 = __PHI (__BB2: in_4(D), __BB4: next_pin_5);
+ pout_6 = __PHI (__BB2: out_7(D), __BB4: next_pout_8);
+ raw_15 = __MEM <const int> (pin_3);
+ x_9 = raw_15 | 1;
+ cmp_10 = x_9 > 65535;
+ neg_11 = -x_9;
+ shifted_12 = neg_11 >> 31;
+ selected_13 = cmp_10 ? shifted_12 : x_9;
+ narrowed_14 = (unsigned short) selected_13;
+ __MEM <unsigned short> (pout_6) = narrowed_14;
+ next_pin_5 = pin_3 + 4ul;
+ next_pout_8 = pout_6 + 2ul;
+ i_2 = i_1 + 1;
+ if (i_2 != 64)
+ goto __BB4;
+ else
+ goto __BB5;
+
+__BB(4):
+ goto __BB3;
+
+__BB(5):
+ return;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-not "\\.SAT_TRUNC" "vect" } } */
--
2.50.1 (Apple Git-155)