Hi!

When POINTER_PLUS_EXPR is vectorized, we vectorize it as a vector PLUS_EXPR.
This (usually?  Not sure about targets where sizetype has different
precision from POINTER_SIZE; maybe those just don't have vector types) works
because we vectorize pointer variables as vectors of unsigned pointer sized
integers and if sizetype has the same precision, then it is the same vector
too, so both operands and result are compatible vectors.

POINTER_DIFF_EXPR is different, the arguments are pointers which get
vectype of vectors of unsigned pointer sized integers, but the result
is a corresponding signed type, so vectype_out is vector of signed pointer
sized integers; those aren't compatible.

So, we can't just vectorize POINTER_DIFF_EXPR as vector MINUS_EXPR, we need
to VCE the result from vectype to vectype_out.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?

2017-12-09  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/83338
        * tree-vect-stmts.c (vectorizable_operation): Handle POINTER_DIFF_EXPR
        vectorization as MINUS_EXPR with a subsequent VIEW_CONVERT_EXPR from
        vector of unsigned integers to vector of signed integers.

        * gcc.dg/vect/pr83338.c: New test.

--- gcc/tree-vect-stmts.c.jj    2017-12-08 12:21:58.000000000 +0100
+++ gcc/tree-vect-stmts.c       2017-12-09 00:55:17.614147824 +0100
@@ -5226,7 +5226,7 @@ vectorizable_operation (gimple *stmt, gi
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
   tree vectype;
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
-  enum tree_code code;
+  enum tree_code code, orig_code;
   machine_mode vec_mode;
   tree new_temp;
   int op_type;
@@ -5264,7 +5264,7 @@ vectorizable_operation (gimple *stmt, gi
   if (TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
     return false;
 
-  code = gimple_assign_rhs_code (stmt);
+  orig_code = code = gimple_assign_rhs_code (stmt);
 
   /* For pointer addition and subtraction, we should use the normal
      plus and minus for the vector operation.  */
@@ -5455,6 +5455,14 @@ vectorizable_operation (gimple *stmt, gi
   /* Handle def.  */
   vec_dest = vect_create_destination_var (scalar_dest, vectype);
 
+  /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as
+     vectors with unsigned elements, but the result is signed.  So, we
+     need to compute the MINUS_EXPR into vectype temporary and
+     VIEW_CONVERT_EXPR it into the final vectype_out result.  */
+  tree vec_cvt_dest = NULL_TREE;
+  if (orig_code == POINTER_DIFF_EXPR)
+    vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
+
   /* In case the vectorization factor (VF) is bigger than the number
      of elements that we can fit in a vectype (nunits), we have to generate
      more than one vector stmt - i.e - we need to "unroll" the
@@ -5546,6 +5554,15 @@ vectorizable_operation (gimple *stmt, gi
          new_temp = make_ssa_name (vec_dest, new_stmt);
          gimple_assign_set_lhs (new_stmt, new_temp);
          vect_finish_stmt_generation (stmt, new_stmt, gsi);
+         if (vec_cvt_dest)
+           {
+             new_temp = build1 (VIEW_CONVERT_EXPR, vectype_out, new_temp);
+             new_stmt = gimple_build_assign (vec_cvt_dest, VIEW_CONVERT_EXPR,
+                                             new_temp);
+             new_temp = make_ssa_name (vec_cvt_dest, new_stmt);
+             gimple_assign_set_lhs (new_stmt, new_temp);
+             vect_finish_stmt_generation (stmt, new_stmt, gsi);
+           }
           if (slp_node)
            SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);
         }
--- gcc/testsuite/gcc.dg/vect/pr83338.c.jj      2017-12-09 01:00:06.602565622 
+0100
+++ gcc/testsuite/gcc.dg/vect/pr83338.c 2017-12-09 01:00:18.297422116 +0100
@@ -0,0 +1,10 @@
+/* PR tree-optimization/83338 */
+/* { dg-do compile } */
+
+void
+foo (char **p, char **q, __PTRDIFF_TYPE__ *r)
+{
+  int i;
+  for (i = 0; i < 1024; i++)
+    r[i] = p[i] - q[i];
+}


        Jakub

Reply via email to