From 485ab50c204ddba922c92d8d467ac734428a4e8a Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 20 Nov 2024 10:04:45 +0000 Subject: [PATCH] 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. --- 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 c1f3558af92..6d28d620eb5 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 931ea63c129..89a7b02ef43 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 * = 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 85f8c73119c..3c82a7b2b02 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 1b7ab31656c..b68355ed8b9 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; + && can_implement_p (op, TYPE_MODE (vector_compute_type))) + return 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); - } - - 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 (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 7a92da00f7d..8ff6f30a2d8 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)