1 /* Tree-based target query functions relating to optabs
2 Copyright (C) 1987-2024 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
25 #include "insn-codes.h"
30 #include "optabs-tree.h"
31 #include "stor-layout.h"
33 /* Return the optab used for computing the operation given by the tree code,
34 CODE and the tree EXP. This function is not always usable (for example, it
35 cannot give complete results for multiplication or division) but probably
36 ought to be relied on more widely throughout the expander. */
38 optab_for_tree_code (enum tree_code code
, const_tree type
,
39 enum optab_subtype subtype
)
51 return one_cmpl_optab
;
56 case MULT_HIGHPART_EXPR
:
57 return TYPE_UNSIGNED (type
) ? umul_highpart_optab
: smul_highpart_optab
;
62 /* {s,u}mod_optab implements TRUNC_MOD_EXPR. For scalar modes,
63 expansion has code to adjust TRUNC_MOD_EXPR into the desired other
64 modes, but for vector modes it does not. The adjustment code
65 should be instead emitted in tree-vect-patterns.cc. */
66 if (VECTOR_TYPE_P (type
))
70 return TYPE_UNSIGNED (type
) ? umod_optab
: smod_optab
;
75 /* {,u}{s,u}div_optab implements {TRUNC,EXACT}_DIV_EXPR or RDIV_EXPR.
76 For scalar modes, expansion has code to adjust TRUNC_DIV_EXPR
77 into the desired other modes, but for vector modes it does not.
78 The adjustment code should be instead emitted in
79 tree-vect-patterns.cc. */
80 if (VECTOR_TYPE_P (type
))
86 if (TYPE_SATURATING (type
))
87 return TYPE_UNSIGNED (type
) ? usdiv_optab
: ssdiv_optab
;
88 return TYPE_UNSIGNED (type
) ? udiv_optab
: sdiv_optab
;
91 if (VECTOR_TYPE_P (type
))
93 if (subtype
== optab_vector
)
94 return TYPE_SATURATING (type
) ? unknown_optab
: vashl_optab
;
96 gcc_assert (subtype
== optab_scalar
);
98 if (TYPE_SATURATING (type
))
99 return TYPE_UNSIGNED (type
) ? usashl_optab
: ssashl_optab
;
103 if (VECTOR_TYPE_P (type
))
105 if (subtype
== optab_vector
)
106 return TYPE_UNSIGNED (type
) ? vlshr_optab
: vashr_optab
;
108 gcc_assert (subtype
== optab_scalar
);
110 return TYPE_UNSIGNED (type
) ? lshr_optab
: ashr_optab
;
113 if (VECTOR_TYPE_P (type
))
115 if (subtype
== optab_vector
)
118 gcc_assert (subtype
== optab_scalar
);
123 if (VECTOR_TYPE_P (type
))
125 if (subtype
== optab_vector
)
128 gcc_assert (subtype
== optab_scalar
);
133 return TYPE_UNSIGNED (type
) ? umax_optab
: smax_optab
;
136 return TYPE_UNSIGNED (type
) ? umin_optab
: smin_optab
;
138 case REALIGN_LOAD_EXPR
:
139 return vec_realign_load_optab
;
142 return TYPE_UNSIGNED (type
) ? usum_widen_optab
: ssum_widen_optab
;
146 if (subtype
== optab_vector_mixed_sign
)
147 return usdot_prod_optab
;
149 return (TYPE_UNSIGNED (type
) ? udot_prod_optab
: sdot_prod_optab
);
153 return TYPE_UNSIGNED (type
) ? usad_optab
: ssad_optab
;
155 case WIDEN_MULT_PLUS_EXPR
:
156 return (TYPE_UNSIGNED (type
)
157 ? (TYPE_SATURATING (type
)
158 ? usmadd_widen_optab
: umadd_widen_optab
)
159 : (TYPE_SATURATING (type
)
160 ? ssmadd_widen_optab
: smadd_widen_optab
));
162 case WIDEN_MULT_MINUS_EXPR
:
163 return (TYPE_UNSIGNED (type
)
164 ? (TYPE_SATURATING (type
)
165 ? usmsub_widen_optab
: umsub_widen_optab
)
166 : (TYPE_SATURATING (type
)
167 ? ssmsub_widen_optab
: smsub_widen_optab
));
169 case VEC_WIDEN_MULT_HI_EXPR
:
170 return (TYPE_UNSIGNED (type
)
171 ? vec_widen_umult_hi_optab
: vec_widen_smult_hi_optab
);
173 case VEC_WIDEN_MULT_LO_EXPR
:
174 return (TYPE_UNSIGNED (type
)
175 ? vec_widen_umult_lo_optab
: vec_widen_smult_lo_optab
);
177 case VEC_WIDEN_MULT_EVEN_EXPR
:
178 return (TYPE_UNSIGNED (type
)
179 ? vec_widen_umult_even_optab
: vec_widen_smult_even_optab
);
181 case VEC_WIDEN_MULT_ODD_EXPR
:
182 return (TYPE_UNSIGNED (type
)
183 ? vec_widen_umult_odd_optab
: vec_widen_smult_odd_optab
);
185 case VEC_WIDEN_LSHIFT_HI_EXPR
:
186 return (TYPE_UNSIGNED (type
)
187 ? vec_widen_ushiftl_hi_optab
: vec_widen_sshiftl_hi_optab
);
189 case VEC_WIDEN_LSHIFT_LO_EXPR
:
190 return (TYPE_UNSIGNED (type
)
191 ? vec_widen_ushiftl_lo_optab
: vec_widen_sshiftl_lo_optab
);
193 case VEC_UNPACK_HI_EXPR
:
194 return (TYPE_UNSIGNED (type
)
195 ? vec_unpacku_hi_optab
: vec_unpacks_hi_optab
);
197 case VEC_UNPACK_LO_EXPR
:
198 return (TYPE_UNSIGNED (type
)
199 ? vec_unpacku_lo_optab
: vec_unpacks_lo_optab
);
201 case VEC_UNPACK_FLOAT_HI_EXPR
:
202 /* The signedness is determined from input operand. */
203 return (TYPE_UNSIGNED (type
)
204 ? vec_unpacku_float_hi_optab
: vec_unpacks_float_hi_optab
);
206 case VEC_UNPACK_FLOAT_LO_EXPR
:
207 /* The signedness is determined from input operand. */
208 return (TYPE_UNSIGNED (type
)
209 ? vec_unpacku_float_lo_optab
: vec_unpacks_float_lo_optab
);
211 case VEC_UNPACK_FIX_TRUNC_HI_EXPR
:
212 /* The signedness is determined from output operand. */
213 return (TYPE_UNSIGNED (type
)
214 ? vec_unpack_ufix_trunc_hi_optab
215 : vec_unpack_sfix_trunc_hi_optab
);
217 case VEC_UNPACK_FIX_TRUNC_LO_EXPR
:
218 /* The signedness is determined from output operand. */
219 return (TYPE_UNSIGNED (type
)
220 ? vec_unpack_ufix_trunc_lo_optab
221 : vec_unpack_sfix_trunc_lo_optab
);
223 case VEC_PACK_TRUNC_EXPR
:
224 return vec_pack_trunc_optab
;
226 case VEC_PACK_SAT_EXPR
:
227 return TYPE_UNSIGNED (type
) ? vec_pack_usat_optab
: vec_pack_ssat_optab
;
229 case VEC_PACK_FIX_TRUNC_EXPR
:
230 /* The signedness is determined from output operand. */
231 return (TYPE_UNSIGNED (type
)
232 ? vec_pack_ufix_trunc_optab
: vec_pack_sfix_trunc_optab
);
234 case VEC_PACK_FLOAT_EXPR
:
235 /* The signedness is determined from input operand. */
236 return (TYPE_UNSIGNED (type
)
237 ? vec_packu_float_optab
: vec_packs_float_optab
);
239 case VEC_DUPLICATE_EXPR
:
240 return vec_duplicate_optab
;
242 case VEC_SERIES_EXPR
:
243 return vec_series_optab
;
249 trapv
= INTEGRAL_TYPE_P (type
) && TYPE_OVERFLOW_TRAPS (type
);
252 case POINTER_PLUS_EXPR
:
254 if (TYPE_SATURATING (type
))
255 return TYPE_UNSIGNED (type
) ? usadd_optab
: ssadd_optab
;
256 return trapv
? addv_optab
: add_optab
;
258 case POINTER_DIFF_EXPR
:
260 if (TYPE_SATURATING (type
))
261 return TYPE_UNSIGNED (type
) ? ussub_optab
: sssub_optab
;
262 return trapv
? subv_optab
: sub_optab
;
265 if (TYPE_SATURATING (type
))
266 return TYPE_UNSIGNED (type
) ? usmul_optab
: ssmul_optab
;
267 return trapv
? smulv_optab
: smul_optab
;
270 if (TYPE_SATURATING (type
))
271 return TYPE_UNSIGNED (type
) ? usneg_optab
: ssneg_optab
;
272 return trapv
? negv_optab
: neg_optab
;
275 return trapv
? absv_optab
: abs_optab
;
280 return unknown_optab
;
284 /* Check whether an operation represented by CODE is a 'half' widening operation
285 in which the input vector type has half the number of bits of the output
286 vector type e.g. V8QI->V8HI.
288 This is handled by widening the inputs using NOP_EXPRs then using a
289 non-widening stmt e.g. MINUS_EXPR. RTL fusing converts these to the widening
290 hardware instructions if supported.
292 The more typical case (handled in supportable_widening_operation) is where
293 the input vector type has the same number of bits as the output vector type.
294 In this case half the elements of the input vectors must be processed at a
295 time into respective vector outputs with elements twice as wide i.e. a
296 'hi'/'lo' pair using codes such as VEC_WIDEN_MINUS_HI/LO.
298 Supported widening operations:
303 - CODE1 - The non-widened code, which will be used after the inputs are
304 converted to the wide type. */
306 supportable_half_widening_operation (enum tree_code code
, tree vectype_out
,
307 tree vectype_in
, enum tree_code
*code1
)
310 enum tree_code dummy_code
;
313 gcc_assert (VECTOR_TYPE_P (vectype_out
) && VECTOR_TYPE_P (vectype_in
));
315 m1
= TYPE_MODE (vectype_out
);
316 m2
= TYPE_MODE (vectype_in
);
318 if (!VECTOR_MODE_P (m1
) || !VECTOR_MODE_P (m2
))
321 if (maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in
),
322 TYPE_VECTOR_SUBPARTS (vectype_out
)))
327 case WIDEN_LSHIFT_EXPR
:
328 *code1
= LSHIFT_EXPR
;
330 case WIDEN_MULT_EXPR
:
337 if (!supportable_convert_operation (NOP_EXPR
, vectype_out
, vectype_in
,
341 op
= optab_for_tree_code (*code1
, vectype_out
, optab_vector
);
342 return (optab_handler (op
, TYPE_MODE (vectype_out
)) != CODE_FOR_nothing
);
345 /* Function supportable_convert_operation
347 Check whether an operation represented by the code CODE is a
348 convert operation that is supported by the target platform in
349 vector form (i.e., when operating on arguments of type VECTYPE_IN
350 producing a result of type VECTYPE_OUT).
352 Convert operations we currently support directly are FIX_TRUNC and FLOAT.
353 This function checks if these operations are supported
354 by the target platform directly (via vector tree-codes).
357 - CODE1 is code of vector operation to be used when
358 vectorizing the operation, if available. */
361 supportable_convert_operation (enum tree_code code
,
362 tree vectype_out
, tree vectype_in
,
363 enum tree_code
*code1
)
368 gcc_assert (VECTOR_TYPE_P (vectype_out
) && VECTOR_TYPE_P (vectype_in
));
370 m1
= TYPE_MODE (vectype_out
);
371 m2
= TYPE_MODE (vectype_in
);
373 if (!VECTOR_MODE_P (m1
) || !VECTOR_MODE_P (m2
))
376 /* First check if we can done conversion directly. */
377 if ((code
== FIX_TRUNC_EXPR
378 && can_fix_p (m1
,m2
,TYPE_UNSIGNED (vectype_out
), &truncp
)
380 || (code
== FLOAT_EXPR
381 && can_float_p (m1
,m2
,TYPE_UNSIGNED (vectype_in
))
382 != CODE_FOR_nothing
))
388 if (GET_MODE_UNIT_PRECISION (m1
) > GET_MODE_UNIT_PRECISION (m2
)
389 && can_extend_p (m1
, m2
, TYPE_UNSIGNED (vectype_in
)))
395 if (GET_MODE_UNIT_PRECISION (m1
) < GET_MODE_UNIT_PRECISION (m2
)
396 && convert_optab_handler (trunc_optab
, m1
, m2
) != CODE_FOR_nothing
)
405 /* Return true iff vec_cmp_optab/vec_cmpu_optab can handle a vector comparison
406 for code CODE, comparing operands of type VALUE_TYPE and producing a result
407 of type MASK_TYPE. */
410 vec_cmp_icode_p (tree value_type
, tree mask_type
, enum tree_code code
)
412 enum rtx_code rcode
= get_rtx_code_1 (code
, TYPE_UNSIGNED (value_type
));
413 if (rcode
== UNKNOWN
)
416 return can_vec_cmp_compare_p (rcode
, TYPE_MODE (value_type
),
417 TYPE_MODE (mask_type
));
420 /* Return true iff vec_cmpeq_optab can handle a vector comparison for code
421 CODE, comparing operands of type VALUE_TYPE and producing a result of type
425 vec_cmp_eq_icode_p (tree value_type
, tree mask_type
, enum tree_code code
)
427 if (code
!= EQ_EXPR
&& code
!= NE_EXPR
)
430 return get_vec_cmp_eq_icode (TYPE_MODE (value_type
), TYPE_MODE (mask_type
))
434 /* Return TRUE if appropriate vector insn is available
435 for vector comparison expr with vector type VALUE_TYPE
436 and resulting mask with MASK_TYPE. */
439 expand_vec_cmp_expr_p (tree value_type
, tree mask_type
, enum tree_code code
)
441 return vec_cmp_icode_p (value_type
, mask_type
, code
)
442 || vec_cmp_eq_icode_p (value_type
, mask_type
, code
);
445 /* Return true iff vcond_optab/vcondu_optab can handle a vector
446 comparison for code CODE, comparing operands of type CMP_OP_TYPE and
447 producing a result of type VALUE_TYPE. */
450 vcond_icode_p (tree value_type
, tree cmp_op_type
, enum tree_code code
)
452 enum rtx_code rcode
= get_rtx_code_1 (code
, TYPE_UNSIGNED (cmp_op_type
));
453 if (rcode
== UNKNOWN
)
456 return can_vcond_compare_p (rcode
, TYPE_MODE (value_type
),
457 TYPE_MODE (cmp_op_type
));
460 /* Return true iff vcondeq_optab can handle a vector comparison for code CODE,
461 comparing operands of type CMP_OP_TYPE and producing a result of type
465 vcond_eq_icode_p (tree value_type
, tree cmp_op_type
, enum tree_code code
)
467 if (code
!= EQ_EXPR
&& code
!= NE_EXPR
)
470 return get_vcond_eq_icode (TYPE_MODE (value_type
), TYPE_MODE (cmp_op_type
))
474 /* Return TRUE iff, appropriate vector insns are available
475 for vector cond expr with vector type VALUE_TYPE and a comparison
476 with operand vector types in CMP_OP_TYPE. */
479 expand_vec_cond_expr_p (tree value_type
, tree cmp_op_type
, enum tree_code code
)
481 machine_mode value_mode
= TYPE_MODE (value_type
);
482 machine_mode cmp_op_mode
= TYPE_MODE (cmp_op_type
);
483 if (VECTOR_BOOLEAN_TYPE_P (cmp_op_type
)
484 && get_vcond_mask_icode (TYPE_MODE (value_type
),
485 TYPE_MODE (cmp_op_type
)) != CODE_FOR_nothing
)
488 if (maybe_ne (GET_MODE_NUNITS (value_mode
), GET_MODE_NUNITS (cmp_op_mode
)))
491 if (TREE_CODE_CLASS (code
) != tcc_comparison
)
492 /* This may happen, for example, if code == SSA_NAME, in which case we
493 cannot be certain whether a vector insn is available. */
496 return vcond_icode_p (value_type
, cmp_op_type
, code
)
497 || vcond_eq_icode_p (value_type
, cmp_op_type
, code
);
500 /* Use the current target and options to initialize
501 TREE_OPTIMIZATION_OPTABS (OPTNODE). */
504 init_tree_optimization_optabs (tree optnode
)
506 /* Quick exit if we have already computed optabs for this target. */
507 if (TREE_OPTIMIZATION_BASE_OPTABS (optnode
) == this_target_optabs
)
510 /* Forget any previous information and set up for the current target. */
511 TREE_OPTIMIZATION_BASE_OPTABS (optnode
) = this_target_optabs
;
512 struct target_optabs
*tmp_optabs
= (struct target_optabs
*)
513 TREE_OPTIMIZATION_OPTABS (optnode
);
515 memset (tmp_optabs
, 0, sizeof (struct target_optabs
));
517 tmp_optabs
= ggc_cleared_alloc
<target_optabs
> ();
519 /* Generate a new set of optabs into tmp_optabs. */
520 init_all_optabs (tmp_optabs
);
522 /* If the optabs changed, record it. */
523 if (memcmp (tmp_optabs
, this_target_optabs
, sizeof (struct target_optabs
)))
524 TREE_OPTIMIZATION_OPTABS (optnode
) = tmp_optabs
;
527 TREE_OPTIMIZATION_OPTABS (optnode
) = NULL
;
528 ggc_free (tmp_optabs
);
532 /* Return TRUE if the target has support for vector right shift of an
533 operand of type TYPE. If OT_TYPE is OPTAB_DEFAULT, check for existence
534 of a shift by either a scalar or a vector. Otherwise, check only
535 for a shift that matches OT_TYPE. */
538 target_supports_op_p (tree type
, enum tree_code code
,
539 enum optab_subtype ot_subtype
)
541 optab ot
= optab_for_tree_code (code
, type
, ot_subtype
);
542 return (ot
!= unknown_optab
543 && optab_handler (ot
, TYPE_MODE (type
)) != CODE_FOR_nothing
);
546 /* Return true if the target has support for masked load/store.
547 We can support masked load/store by either mask{load,store}
548 or mask_len_{load,store}.
549 This helper function checks whether target supports masked
550 load/store and return corresponding IFN in the last argument
551 (IFN_MASK_{LOAD,STORE} or IFN_MASK_LEN_{LOAD,STORE}). */
554 target_supports_mask_load_store_p (machine_mode mode
, machine_mode mask_mode
,
555 bool is_load
, internal_fn
*ifn
)
557 optab op
= is_load
? maskload_optab
: maskstore_optab
;
558 optab len_op
= is_load
? mask_len_load_optab
: mask_len_store_optab
;
559 if (convert_optab_handler (op
, mode
, mask_mode
) != CODE_FOR_nothing
)
562 *ifn
= is_load
? IFN_MASK_LOAD
: IFN_MASK_STORE
;
565 else if (convert_optab_handler (len_op
, mode
, mask_mode
) != CODE_FOR_nothing
)
568 *ifn
= is_load
? IFN_MASK_LEN_LOAD
: IFN_MASK_LEN_STORE
;
574 /* Return true if target supports vector masked load/store for mode.
575 An additional output in the last argument which is the IFN pointer.
576 We set IFN as MASK_{LOAD,STORE} or MASK_LEN_{LOAD,STORE} according
577 which optab is supported in the target. */
580 can_vec_mask_load_store_p (machine_mode mode
,
581 machine_mode mask_mode
,
587 /* If mode is vector mode, check it directly. */
588 if (VECTOR_MODE_P (mode
))
589 return target_supports_mask_load_store_p (mode
, mask_mode
, is_load
, ifn
);
591 /* Otherwise, return true if there is some vector mode with
592 the mask load/store supported. */
594 /* See if there is any chance the mask load or store might be
595 vectorized. If not, punt. */
597 if (!is_a
<scalar_mode
> (mode
, &smode
))
600 vmode
= targetm
.vectorize
.preferred_simd_mode (smode
);
601 if (VECTOR_MODE_P (vmode
)
602 && targetm
.vectorize
.get_mask_mode (vmode
).exists (&mask_mode
)
603 && target_supports_mask_load_store_p (vmode
, mask_mode
, is_load
, ifn
))
606 auto_vector_modes vector_modes
;
607 targetm
.vectorize
.autovectorize_vector_modes (&vector_modes
, true);
608 for (machine_mode base_mode
: vector_modes
)
609 if (related_vector_mode (base_mode
, smode
).exists (&vmode
)
610 && targetm
.vectorize
.get_mask_mode (vmode
).exists (&mask_mode
)
611 && target_supports_mask_load_store_p (vmode
, mask_mode
, is_load
, ifn
))
616 /* Return true if the target has support for len load/store.
617 We can support len load/store by either len_{load,store}
618 or mask_len_{load,store}.
619 This helper function checks whether target supports len
620 load/store and return corresponding IFN in the last argument
621 (IFN_LEN_{LOAD,STORE} or IFN_MASK_LEN_{LOAD,STORE}). */
624 target_supports_len_load_store_p (machine_mode mode
, bool is_load
,
627 optab op
= is_load
? len_load_optab
: len_store_optab
;
628 optab masked_op
= is_load
? mask_len_load_optab
: mask_len_store_optab
;
630 if (direct_optab_handler (op
, mode
))
633 *ifn
= is_load
? IFN_LEN_LOAD
: IFN_LEN_STORE
;
636 machine_mode mask_mode
;
637 if (targetm
.vectorize
.get_mask_mode (mode
).exists (&mask_mode
)
638 && convert_optab_handler (masked_op
, mode
, mask_mode
) != CODE_FOR_nothing
)
641 *ifn
= is_load
? IFN_MASK_LEN_LOAD
: IFN_MASK_LEN_STORE
;
647 /* If target supports vector load/store with length for vector mode MODE,
648 return the corresponding vector mode, otherwise return opt_machine_mode ().
649 There are two flavors for vector load/store with length, one is to measure
650 length with bytes, the other is to measure length with lanes.
651 As len_{load,store} optabs point out, for the flavor with bytes, we use
652 VnQI to wrap the other supportable same size vector modes.
653 An additional output in the last argument which is the IFN pointer.
654 We set IFN as LEN_{LOAD,STORE} or MASK_LEN_{LOAD,STORE} according
655 which optab is supported in the target. */
658 get_len_load_store_mode (machine_mode mode
, bool is_load
, internal_fn
*ifn
)
660 gcc_assert (VECTOR_MODE_P (mode
));
662 /* Check if length in lanes supported for this mode directly. */
663 if (target_supports_len_load_store_p (mode
, is_load
, ifn
))
666 /* Check if length in bytes supported for same vector size VnQI. */
668 poly_uint64 nunits
= GET_MODE_SIZE (mode
);
669 if (related_vector_mode (mode
, QImode
, nunits
).exists (&vmode
)
670 && target_supports_len_load_store_p (vmode
, is_load
, ifn
))
673 return opt_machine_mode ();