https://gcc.gnu.org/g:485ab50c204ddba922c92d8d467ac734428a4e8a

commit r15-5493-g485ab50c204ddba922c92d8d467ac734428a4e8a
Author: Richard Sandiford <richard.sandif...@arm.com>
Date:   Wed Nov 20 10:04:45 2024 +0000

    Add helpers to test whether an optab can be implemented
    
    The vectoriser and vector lowering passes both had tests of the form:
    
        if (op
            && (optab_handler (op, compute_mode) != CODE_FOR_nothing
                || optab_libfunc (op, compute_mode)))
          ...success...
        if (code == MULT_HIGHPART_EXPR
            && can_mult_highpart_p (compute_mode,
                                    TYPE_UNSIGNED (compute_type)))
          ...success...
    
    This patch adds helper routines for this kind of test, so that it's
    easier to handle other optab alternatives in a similar way.
    
    gcc/
            * optabs-query.cc (can_open_code_p, can_implement_p): Declare.
            * optabs-query.h (can_open_code_p, can_implement_p): New functions.
            * optabs-tree.cc (target_supports_op_p): Use can_implement_p.
            * tree-vect-stmts.cc (vectorizable_operation): Likewise.
            * tree-vect-generic.cc (get_compute_type): Likewise.  Remove code
            parameter.
            (expand_vector_scalar_condition, expand_vector_conversion)
            (expand_vector_operations_1): Update calls accordingly.

Diff:
---
 gcc/optabs-query.cc      | 30 ++++++++++++++++++++
 gcc/optabs-query.h       |  2 ++
 gcc/optabs-tree.cc       |  3 +-
 gcc/tree-vect-generic.cc | 74 ++++++++++++++++++------------------------------
 gcc/tree-vect-stmts.cc   | 20 +++++--------
 5 files changed, 67 insertions(+), 62 deletions(-)

diff --git a/gcc/optabs-query.cc b/gcc/optabs-query.cc
index c1f3558af920..6d28d620eb51 100644
--- a/gcc/optabs-query.cc
+++ b/gcc/optabs-query.cc
@@ -781,3 +781,33 @@ can_vec_extract (machine_mode mode, machine_mode extr_mode)
   /* We assume we can pun mode to vmode and imode to extr_mode.  */
   return true;
 }
+
+/* Return true if we can implement OP for mode MODE directly, without resorting
+   to a libfunc.   This usually means that OP will be implemented inline.
+
+   Note that this function cannot tell whether the target pattern chooses to
+   use libfuncs internally.  */
+
+bool
+can_open_code_p (optab op, machine_mode mode)
+{
+  if (optab_handler (op, mode) != CODE_FOR_nothing)
+    return true;
+
+  if (op == umul_highpart_optab)
+    return can_mult_highpart_p (mode, true);
+
+  if (op == smul_highpart_optab)
+    return can_mult_highpart_p (mode, false);
+
+  return false;
+}
+
+/* Return true if we can implement OP for mode MODE in some way, either by
+   open-coding it or by calling a libfunc.  */
+
+bool
+can_implement_p (optab op, machine_mode mode)
+{
+  return can_open_code_p (op, mode) || optab_libfunc (op, mode);
+}
diff --git a/gcc/optabs-query.h b/gcc/optabs-query.h
index 931ea63c129e..89a7b02ef437 100644
--- a/gcc/optabs-query.h
+++ b/gcc/optabs-query.h
@@ -172,6 +172,8 @@ bool supports_vec_gather_load_p (machine_mode = E_VOIDmode,
                                 vec<int> * = nullptr);
 bool supports_vec_scatter_store_p (machine_mode = E_VOIDmode);
 bool can_vec_extract (machine_mode, machine_mode);
+bool can_open_code_p (optab, machine_mode);
+bool can_implement_p (optab, machine_mode);
 
 /* Version of find_widening_optab_handler_and_mode that operates on
    specific mode types.  */
diff --git a/gcc/optabs-tree.cc b/gcc/optabs-tree.cc
index 85f8c73119c1..3c82a7b2b02b 100644
--- a/gcc/optabs-tree.cc
+++ b/gcc/optabs-tree.cc
@@ -504,8 +504,7 @@ target_supports_op_p (tree type, enum tree_code code,
                      enum optab_subtype ot_subtype)
 {
   optab ot = optab_for_tree_code (code, type, ot_subtype);
-  return (ot != unknown_optab
-         && optab_handler (ot, TYPE_MODE (type)) != CODE_FOR_nothing);
+  return ot != unknown_optab && can_implement_p (ot, TYPE_MODE (type));
 }
 
 /* Return true if the target has support for masked load/store.
diff --git a/gcc/tree-vect-generic.cc b/gcc/tree-vect-generic.cc
index 1b7ab31656c5..b68355ed8b96 100644
--- a/gcc/tree-vect-generic.cc
+++ b/gcc/tree-vect-generic.cc
@@ -1602,49 +1602,29 @@ ssa_uniform_vector_p (tree op)
   return NULL_TREE;
 }
 
-/* Return type in which CODE operation with optab OP can be
-   computed.  */
+/* Return the type that should be used to implement OP on type TYPE.
+   This is TYPE itself if the target can do the operation directly,
+   otherwise it is a scalar type or a smaller vector type.  */
 
 static tree
-get_compute_type (enum tree_code code, optab op, tree type)
+get_compute_type (optab op, tree type)
 {
-  /* For very wide vectors, try using a smaller vector mode.  */
-  tree compute_type = type;
-  if (op
-      && (!VECTOR_MODE_P (TYPE_MODE (type))
-         || optab_handler (op, TYPE_MODE (type)) == CODE_FOR_nothing))
+  if (op)
     {
-      tree vector_compute_type
-       = type_for_widest_vector_mode (type, op);
+      if (VECTOR_MODE_P (TYPE_MODE (type))
+         && can_implement_p (op, TYPE_MODE (type)))
+       return type;
+
+      /* For very wide vectors, try using a smaller vector mode.  */
+      tree vector_compute_type = type_for_widest_vector_mode (type, op);
       if (vector_compute_type != NULL_TREE
          && maybe_ne (TYPE_VECTOR_SUBPARTS (vector_compute_type), 1U)
-         && (optab_handler (op, TYPE_MODE (vector_compute_type))
-             != CODE_FOR_nothing))
-       compute_type = vector_compute_type;
-    }
-
-  /* If we are breaking a BLKmode vector into smaller pieces,
-     type_for_widest_vector_mode has already looked into the optab,
-     so skip these checks.  */
-  if (compute_type == type)
-    {
-      machine_mode compute_mode = TYPE_MODE (compute_type);
-      if (VECTOR_MODE_P (compute_mode))
-       {
-         if (op
-             && (optab_handler (op, compute_mode) != CODE_FOR_nothing
-                 || optab_libfunc (op, compute_mode)))
-           return compute_type;
-         if (code == MULT_HIGHPART_EXPR
-             && can_mult_highpart_p (compute_mode,
-                                     TYPE_UNSIGNED (compute_type)))
-           return compute_type;
-       }
-      /* There is no operation in hardware, so fall back to scalars.  */
-      compute_type = TREE_TYPE (type);
+         && can_implement_p (op, TYPE_MODE (vector_compute_type)))
+       return vector_compute_type;
     }
 
-  return compute_type;
+  /* There is no operation in hardware, so fall back to scalars.  */
+  return TREE_TYPE (type);
 }
 
 static tree
@@ -1667,7 +1647,7 @@ expand_vector_scalar_condition (gimple_stmt_iterator *gsi)
   gassign *stmt = as_a <gassign *> (gsi_stmt (*gsi));
   tree lhs = gimple_assign_lhs (stmt);
   tree type = TREE_TYPE (lhs);
-  tree compute_type = get_compute_type (COND_EXPR, mov_optab, type);
+  tree compute_type = get_compute_type (mov_optab, type);
   machine_mode compute_mode = TYPE_MODE (compute_type);
   gcc_assert (compute_mode != BLKmode);
   tree rhs2 = gimple_assign_rhs2 (stmt);
@@ -1850,7 +1830,7 @@ expand_vector_conversion (gimple_stmt_iterator *gsi)
        }
 
       if (optab1)
-       compute_type = get_compute_type (code1, optab1, arg_type);
+       compute_type = get_compute_type (optab1, arg_type);
       enum insn_code icode1;
       if (VECTOR_TYPE_P (compute_type)
          && ((icode1 = optab_handler (optab1, TYPE_MODE (compute_type)))
@@ -1931,7 +1911,7 @@ expand_vector_conversion (gimple_stmt_iterator *gsi)
        }
 
       if (optab1 && optab2)
-       compute_type = get_compute_type (code1, optab1, arg_type);
+       compute_type = get_compute_type (optab1, arg_type);
 
       enum insn_code icode1, icode2;
       if (VECTOR_TYPE_P (compute_type)
@@ -2184,12 +2164,12 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
        {
           op = optab_for_tree_code (code, type, optab_scalar);
 
-         compute_type = get_compute_type (code, op, type);
+         compute_type = get_compute_type (op, type);
          if (compute_type == type)
            return;
          /* The rtl expander will expand vector/scalar as vector/vector
             if necessary.  Pick one with wider vector type.  */
-         tree compute_vtype = get_compute_type (code, opv, type);
+         tree compute_vtype = get_compute_type (opv, type);
          if (subparts_gt (compute_vtype, compute_type))
            {
              compute_type = compute_vtype;
@@ -2200,7 +2180,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
       if (code == LROTATE_EXPR || code == RROTATE_EXPR)
        {
          if (compute_type == NULL_TREE)
-           compute_type = get_compute_type (code, op, type);
+           compute_type = get_compute_type (op, type);
          if (compute_type == type)
            return;
          /* Before splitting vector rotates into scalar rotates,
@@ -2213,11 +2193,11 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
            {
              optab oplv = vashl_optab, opl = ashl_optab;
              optab oprv = vlshr_optab, opr = lshr_optab, opo = ior_optab;
-             tree compute_lvtype = get_compute_type (LSHIFT_EXPR, oplv, type);
-             tree compute_rvtype = get_compute_type (RSHIFT_EXPR, oprv, type);
-             tree compute_otype = get_compute_type (BIT_IOR_EXPR, opo, type);
-             tree compute_ltype = get_compute_type (LSHIFT_EXPR, opl, type);
-             tree compute_rtype = get_compute_type (RSHIFT_EXPR, opr, type);
+             tree compute_lvtype = get_compute_type (oplv, type);
+             tree compute_rvtype = get_compute_type (oprv, type);
+             tree compute_otype = get_compute_type (opo, type);
+             tree compute_ltype = get_compute_type (opl, type);
+             tree compute_rtype = get_compute_type (opr, type);
              /* The rtl expander will expand vector/scalar as vector/vector
                 if necessary.  Pick one with wider vector type.  */
              if (subparts_gt (compute_lvtype, compute_ltype))
@@ -2263,7 +2243,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
     op = optab_for_tree_code (MINUS_EXPR, type, optab_default);
 
   if (compute_type == NULL_TREE)
-    compute_type = get_compute_type (code, op, type);
+    compute_type = get_compute_type (op, type);
   if (compute_type == type)
     return;
 
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 7a92da00f7dd..8ff6f30a2d89 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -6904,21 +6904,15 @@ vectorizable_operation (vec_info *vinfo,
   /* Supportable by target?  */
 
   vec_mode = TYPE_MODE (vectype);
-  if (code == MULT_HIGHPART_EXPR)
-    target_support_p = can_mult_highpart_p (vec_mode, TYPE_UNSIGNED (vectype));
-  else
+  optab = optab_for_tree_code (code, vectype, optab_default);
+  if (!optab)
     {
-      optab = optab_for_tree_code (code, vectype, optab_default);
-      if (!optab)
-       {
-          if (dump_enabled_p ())
-            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                             "no optab.\n");
-         return false;
-       }
-      target_support_p = (optab_handler (optab, vec_mode) != CODE_FOR_nothing
-                         || optab_libfunc (optab, vec_mode));
+      if (dump_enabled_p ())
+       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                        "no optab.\n");
+      return false;
     }
+  target_support_p = can_implement_p (optab, vec_mode);
 
   bool using_emulated_vectors_p = vect_emulated_vector_p (vectype);
   if (!target_support_p || using_emulated_vectors_p)

Reply via email to