]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add helpers to test whether an optab can be implemented
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 20 Nov 2024 10:04:45 +0000 (10:04 +0000)
committerRichard Sandiford <richard.sandiford@arm.com>
Wed, 20 Nov 2024 10:04:45 +0000 (10:04 +0000)
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.

gcc/optabs-query.cc
gcc/optabs-query.h
gcc/optabs-tree.cc
gcc/tree-vect-generic.cc
gcc/tree-vect-stmts.cc

index c1f3558af920fc4f5c226cc6c318bcc8a4148588..6d28d620eb5143f6ebb9c98fe95ebc0226c5fe15 100644 (file)
@@ -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);
+}
index 931ea63c129e1c346e4f26294117e8c24d479f3d..89a7b02ef43747a8b5e0218fb4bb6875804916cd 100644 (file)
@@ -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.  */
index 85f8c73119c16ff28b50e412bcaf8fe87320bde6..3c82a7b2b02ba85eeaa957613073a2a2ee66afb4 100644 (file)
@@ -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.
index 1b7ab31656c57be285e7e8c062aa00b53edf5af1..b68355ed8b96476e3cd06c38565b03a38ab07331 100644 (file)
@@ -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;
 
index 7a92da00f7ddcfdf146fa1c2511f609e8bc40e9e..8ff6f30a2d8997b18b88c6e858821dec0d3da239 100644 (file)
@@ -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)