]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/110838 - vectorization of widened right shifts
authorRichard Biener <rguenther@suse.de>
Fri, 4 Aug 2023 10:11:45 +0000 (12:11 +0200)
committerRichard Biener <rguenther@suse.de>
Fri, 4 Aug 2023 11:15:05 +0000 (13:15 +0200)
The following fixes a problem with my last attempt of avoiding
out-of-bound shift values for vectorized right shifts of widened
operands.  Instead of truncating the shift amount with a bitwise
and we actually need to saturate it to the target precision.

The following does that and adds test coverage for the constant
and invariant but variable case that would previously have failed.

PR tree-optimization/110838
* tree-vect-patterns.cc (vect_recog_over_widening_pattern):
Fix right-shift value sanitizing.  Properly emit external
def mangling in the preheader rather than in the pattern
def sequence where it will fail vectorizing.

* gcc.dg/vect/pr110838.c: New testcase.

gcc/testsuite/gcc.dg/vect/pr110838.c [new file with mode: 0644]
gcc/tree-vect-patterns.cc

diff --git a/gcc/testsuite/gcc.dg/vect/pr110838.c b/gcc/testsuite/gcc.dg/vect/pr110838.c
new file mode 100644 (file)
index 0000000..cf8765b
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+
+#include "tree-vect.h"
+
+short a[32], b[32];
+
+void __attribute__((noipa)) foo ()
+{
+  for (int i = 0; i < 32; ++i)
+    a[i] = b[i] >> 16;
+}
+
+void __attribute__((noipa)) bar (int n)
+{
+  int np = n & 31;
+  for (int i = 0; i < 32; ++i)
+    a[i] = b[i] >> np;
+}
+
+int main ()
+{
+  check_vect ();
+  b[0] = -8;
+  foo ();
+  if (a[0] != -1)
+    abort ();
+  bar (16);
+  if (a[0] != -1)
+    abort ();
+  return 0;
+}
index e4ab8c2d65b47d02ead1cea46f81aa74b4454fd8..2cedf23845056173996abd22cef6b9c7857414de 100644 (file)
@@ -3109,8 +3109,8 @@ vect_recog_over_widening_pattern (vec_info *vinfo,
       wide_int min_value, max_value;
       if (TREE_CODE (ops[1]) == INTEGER_CST)
        ops[1] = wide_int_to_tree (op_type,
-                                  wi::bit_and (wi::to_wide (ops[1]),
-                                               new_precision - 1));
+                                  wi::umin (wi::to_wide (ops[1]),
+                                            new_precision - 1));
       else if (!vect_get_range_info (ops[1], &min_value, &max_value)
               || wi::ge_p (max_value, new_precision, TYPE_SIGN (op_type)))
        {
@@ -3118,11 +3118,23 @@ vect_recog_over_widening_pattern (vec_info *vinfo,
             same argument widened shifts and it un-CSEs same arguments.  */
          tree new_var = vect_recog_temp_ssa_var (op_type, NULL);
          gimple *pattern_stmt
-           = gimple_build_assign (new_var, BIT_AND_EXPR, ops[1],
+           = gimple_build_assign (new_var, MIN_EXPR, ops[1],
                                   build_int_cst (op_type, new_precision - 1));
-         ops[1] = new_var;
          gimple_set_location (pattern_stmt, gimple_location (last_stmt));
-         append_pattern_def_seq (vinfo, last_stmt_info, pattern_stmt);
+         if (unprom[1].dt == vect_external_def)
+           {
+             if (edge e = vect_get_external_def_edge (vinfo, ops[1]))
+               {
+                 basic_block new_bb
+                   = gsi_insert_on_edge_immediate (e, pattern_stmt);
+                 gcc_assert (!new_bb);
+               }
+             else
+               return NULL;
+           }
+         else
+           append_pattern_def_seq (vinfo, last_stmt_info, pattern_stmt);
+         ops[1] = new_var;
        }
     }