Hi!

The following testcase ICEs, because after the veclower pass which is the
last point which lowers unsupported vector operations to supported ones
(or scalars) match.pd simplifies a supported vector operation into
unsupported one (vec << 1 >> 1 into vec & { ~1, ... }).
Guarding each match.pd pattern that could do it manually would be IMHO a
nightmare and it could affect hundreds of them, so this patch instead
performs the verification and punting in the infrastructure (of course only
in PROP_gimple_lvec state which is set after the vector lowering).
The function attempts to match expand_vector_operations_1 (except I haven't
added VEC_PERM_EXPR, VEC_COND_EXPR and COND_EXPR cases there, so those
aren't checked and can be added later if we find it a problem).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2021-02-02  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/98287
        * gimple-match.h (check_gimple_lvec): New declaration.
        * gimple-match-head.c (check_gimple_lvec): New function.
        (maybe_push_res_to_seq): Use it.
        * gimple-fold.c: Include tree-pass.h.
        (replace_stmt_with_simplification): Use it.

        * gcc.dg/pr98287.c: New test.

--- gcc/gimple-match.h.jj       2021-01-04 10:25:38.456238093 +0100
+++ gcc/gimple-match.h  2021-02-01 13:19:30.393860766 +0100
@@ -335,6 +335,7 @@ extern tree (*mprts_hook) (gimple_match_
 
 bool gimple_simplify (gimple *, gimple_match_op *, gimple_seq *,
                      tree (*)(tree), tree (*)(tree));
+bool check_gimple_lvec (gimple_match_op *);
 tree maybe_push_res_to_seq (gimple_match_op *, gimple_seq *,
                            tree res = NULL_TREE);
 void maybe_build_generic_op (gimple_match_op *);
--- gcc/gimple-match-head.c.jj  2021-01-16 19:46:53.511672837 +0100
+++ gcc/gimple-match-head.c     2021-02-01 13:18:58.676225427 +0100
@@ -549,6 +549,109 @@ build_call_internal (internal_fn fn, gim
                                     res_op->op_or_null (4));
 }
 
+/* In PROP_gimple_lvec mode, perform extra checking if RES_OP and return
+   true if RES_OP is not appropriate - would require vector operations that
+   would need to be lowered before expansion.  */
+
+bool
+check_gimple_lvec (gimple_match_op *res_op)
+{
+  enum tree_code code = res_op->code;
+  enum gimple_rhs_class rhs_class = get_gimple_rhs_class (code);
+  if (rhs_class != GIMPLE_UNARY_RHS && rhs_class != GIMPLE_BINARY_RHS)
+    return false;
+
+  tree rhs1 = res_op->op_or_null (0);
+  tree rhs2 = res_op->op_or_null (1);
+  tree type = res_op->type;
+
+  if (!VECTOR_TYPE_P (type) || !VECTOR_TYPE_P (TREE_TYPE (rhs1)))
+    return false;
+
+  /* A scalar operation pretending to be a vector one.  */
+  if (VECTOR_BOOLEAN_TYPE_P (type)
+      && !VECTOR_MODE_P (TYPE_MODE (type))
+      && TYPE_MODE (type) != BLKmode
+      && (TREE_CODE_CLASS (code) != tcc_comparison
+         || (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (rhs1))
+             && !VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (rhs1)))
+             && TYPE_MODE (TREE_TYPE (rhs1)) != BLKmode)))
+    return false;
+
+  machine_mode mode = TYPE_MODE (type);
+  optab op;
+  switch (code)
+    {
+    CASE_CONVERT:
+    case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case VIEW_CONVERT_EXPR:
+      return false;
+
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+    case VEC_PACK_FLOAT_EXPR:
+      return false;
+
+    case WIDEN_SUM_EXPR:
+    case VEC_WIDEN_PLUS_HI_EXPR:
+    case VEC_WIDEN_PLUS_LO_EXPR:
+    case VEC_WIDEN_MINUS_HI_EXPR:
+    case VEC_WIDEN_MINUS_LO_EXPR:
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+    case VEC_WIDEN_MULT_EVEN_EXPR:
+    case VEC_WIDEN_MULT_ODD_EXPR:
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+    case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
+    case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
+    case VEC_PACK_TRUNC_EXPR:
+    case VEC_PACK_SAT_EXPR:
+    case VEC_PACK_FIX_TRUNC_EXPR:
+    case VEC_WIDEN_LSHIFT_HI_EXPR:
+    case VEC_WIDEN_LSHIFT_LO_EXPR:
+      return false;
+
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      if (!VECTOR_MODE_P (mode))
+       return true;
+      if (!VECTOR_INTEGER_TYPE_P (TREE_TYPE (rhs2)))
+       {
+         op = optab_for_tree_code (code, type, optab_scalar);
+         if (op && optab_handler (op, mode) != CODE_FOR_nothing)
+           return false;
+       }
+      op = optab_for_tree_code (code, type, optab_vector);
+      if (op && optab_handler (op, mode) != CODE_FOR_nothing)
+       return false;
+      return true;
+
+    case MULT_HIGHPART_EXPR:
+      if (!VECTOR_MODE_P (mode)
+         || !can_mult_highpart_p (mode, TYPE_UNSIGNED (type)))
+       return true;
+      return false;
+
+    default:
+      if (!VECTOR_MODE_P (mode))
+       return true;
+      op = optab_for_tree_code (code, type, optab_default);
+      if (op == unknown_optab
+         && code == NEGATE_EXPR
+         && INTEGRAL_TYPE_P (TREE_TYPE (type)))
+       op = optab_for_tree_code (MINUS_EXPR, type, optab_default);
+      if (op && optab_handler (op, mode) != CODE_FOR_nothing)
+       return false;
+      return true;
+    }
+
+  return false;
+}
+
 /* Push the exploded expression described by RES_OP as a statement to
    SEQ if necessary and return a gimple value denoting the value of the
    expression.  If RES is not NULL then the result will be always RES
@@ -597,6 +700,12 @@ maybe_push_res_to_seq (gimple_match_op *
 
   if (res_op->code.is_tree_code ())
     {
+      if (VECTOR_TYPE_P (res_op->type)
+         && cfun
+         && (cfun->curr_properties & PROP_gimple_lvec) != 0
+         && check_gimple_lvec (res_op))
+       return NULL_TREE;
+
       if (!res)
        {
          if (gimple_in_ssa_p (cfun))
--- gcc/gimple-fold.c.jj        2021-01-22 11:41:56.510499898 +0100
+++ gcc/gimple-fold.c   2021-02-01 13:22:11.992002840 +0100
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.
 #include "tree-vector-builder.h"
 #include "tree-ssa-strlen.h"
 #include "varasm.h"
+#include "tree-pass.h"
 
 enum strlen_range_kind {
   /* Compute the exact constant string length.  */
@@ -5678,6 +5679,11 @@ replace_stmt_with_simplification (gimple
       if (!inplace
          || gimple_num_ops (stmt) > get_gimple_rhs_num_ops (res_op->code))
        {
+         if (VECTOR_TYPE_P (res_op->type)
+             && cfun
+             && (cfun->curr_properties & PROP_gimple_lvec) != 0
+             && check_gimple_lvec (res_op))
+           return false;
          maybe_build_generic_op (res_op);
          gimple_assign_set_rhs_with_ops (gsi, res_op->code,
                                          res_op->op_or_null (0),
--- gcc/testsuite/gcc.dg/pr98287.c.jj   2021-02-01 13:32:22.735981006 +0100
+++ gcc/testsuite/gcc.dg/pr98287.c      2021-02-01 13:32:01.155229122 +0100
@@ -0,0 +1,19 @@
+/* PR tree-optimization/98287 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-ccp -fno-tree-forwprop -Wno-psabi -w" } */
+
+typedef unsigned long __attribute__((__vector_size__ (8))) V;
+V v;
+
+static __attribute__((noinline, noclone)) V
+bar (unsigned short s)
+{
+  return v >> s << s | v >> s >> 63;
+}
+
+unsigned long
+foo (void)
+{
+  V x = bar (1);
+  return x[0];
+}

        Jakub

Reply via email to