libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / optabs-query.cc
blobcc52bc0f5ea74e582182010291ead77f0bbb9fad
1 /* IR-agnostic 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
9 version.
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
14 for more details.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "target.h"
25 #include "insn-codes.h"
26 #include "optabs-query.h"
27 #include "optabs-libfuncs.h"
28 #include "insn-config.h"
29 #include "rtl.h"
30 #include "recog.h"
31 #include "vec-perm-indices.h"
33 struct target_optabs default_target_optabs;
34 struct target_optabs *this_fn_optabs = &default_target_optabs;
35 #if SWITCHABLE_TARGET
36 struct target_optabs *this_target_optabs = &default_target_optabs;
37 #endif
39 /* Return the insn used to perform conversion OP from mode FROM_MODE
40 to mode TO_MODE; return CODE_FOR_nothing if the target does not have
41 such an insn, or if it is unsuitable for optimization type OPT_TYPE. */
43 insn_code
44 convert_optab_handler (convert_optab optab, machine_mode to_mode,
45 machine_mode from_mode, optimization_type opt_type)
47 insn_code icode = convert_optab_handler (optab, to_mode, from_mode);
48 if (icode == CODE_FOR_nothing
49 || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type))
50 return CODE_FOR_nothing;
51 return icode;
54 /* Return the insn used to implement mode MODE of OP; return
55 CODE_FOR_nothing if the target does not have such an insn,
56 or if it is unsuitable for optimization type OPT_TYPE. */
58 insn_code
59 direct_optab_handler (convert_optab optab, machine_mode mode,
60 optimization_type opt_type)
62 insn_code icode = direct_optab_handler (optab, mode);
63 if (icode == CODE_FOR_nothing
64 || !targetm.optab_supported_p (optab, mode, mode, opt_type))
65 return CODE_FOR_nothing;
66 return icode;
69 /* Enumerates the possible types of structure operand to an
70 extraction_insn. */
71 enum extraction_type { ET_unaligned_mem, ET_reg };
73 /* Check whether insv, extv or extzv pattern ICODE can be used for an
74 insertion or extraction of type TYPE on a structure of mode MODE.
75 Return true if so and fill in *INSN accordingly. STRUCT_OP is the
76 operand number of the structure (the first sign_extract or zero_extract
77 operand) and FIELD_OP is the operand number of the field (the other
78 side of the set from the sign_extract or zero_extract). */
80 static bool
81 get_traditional_extraction_insn (extraction_insn *insn,
82 enum extraction_type type,
83 machine_mode mode,
84 enum insn_code icode,
85 int struct_op, int field_op)
87 const struct insn_data_d *data = &insn_data[icode];
89 machine_mode struct_mode = data->operand[struct_op].mode;
90 if (struct_mode == VOIDmode)
91 struct_mode = word_mode;
92 if (mode != struct_mode)
93 return false;
95 machine_mode field_mode = data->operand[field_op].mode;
96 if (field_mode == VOIDmode)
97 field_mode = word_mode;
99 machine_mode pos_mode = data->operand[struct_op + 2].mode;
100 if (pos_mode == VOIDmode)
101 pos_mode = word_mode;
103 insn->icode = icode;
104 insn->field_mode = as_a <scalar_int_mode> (field_mode);
105 if (type == ET_unaligned_mem)
106 insn->struct_mode = byte_mode;
107 else if (struct_mode == BLKmode)
108 insn->struct_mode = opt_scalar_int_mode ();
109 else
110 insn->struct_mode = as_a <scalar_int_mode> (struct_mode);
111 insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
112 return true;
115 /* Return true if an optab exists to perform an insertion or extraction
116 of type TYPE in mode MODE. Describe the instruction in *INSN if so.
118 REG_OPTAB is the optab to use for register structures and
119 MISALIGN_OPTAB is the optab to use for misaligned memory structures.
120 POS_OP is the operand number of the bit position. */
122 static bool
123 get_optab_extraction_insn (class extraction_insn *insn,
124 enum extraction_type type,
125 machine_mode mode, direct_optab reg_optab,
126 direct_optab misalign_optab, int pos_op)
128 direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
129 enum insn_code icode = direct_optab_handler (optab, mode);
130 if (icode == CODE_FOR_nothing)
131 return false;
133 const struct insn_data_d *data = &insn_data[icode];
135 machine_mode pos_mode = data->operand[pos_op].mode;
136 if (pos_mode == VOIDmode)
137 pos_mode = word_mode;
139 insn->icode = icode;
140 insn->field_mode = as_a <scalar_int_mode> (mode);
141 if (type == ET_unaligned_mem)
142 insn->struct_mode = opt_scalar_int_mode ();
143 else
144 insn->struct_mode = insn->field_mode;
145 insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
146 return true;
149 /* Return true if an instruction exists to perform an insertion or
150 extraction (PATTERN says which) of type TYPE in mode MODE.
151 Describe the instruction in *INSN if so. */
153 static bool
154 get_extraction_insn (extraction_insn *insn,
155 enum extraction_pattern pattern,
156 enum extraction_type type,
157 machine_mode mode)
159 switch (pattern)
161 case EP_insv:
162 if (targetm.have_insv ()
163 && get_traditional_extraction_insn (insn, type, mode,
164 targetm.code_for_insv, 0, 3))
165 return true;
166 return get_optab_extraction_insn (insn, type, mode, insv_optab,
167 insvmisalign_optab, 2);
169 case EP_extv:
170 if (targetm.have_extv ()
171 && get_traditional_extraction_insn (insn, type, mode,
172 targetm.code_for_extv, 1, 0))
173 return true;
174 return get_optab_extraction_insn (insn, type, mode, extv_optab,
175 extvmisalign_optab, 3);
177 case EP_extzv:
178 if (targetm.have_extzv ()
179 && get_traditional_extraction_insn (insn, type, mode,
180 targetm.code_for_extzv, 1, 0))
181 return true;
182 return get_optab_extraction_insn (insn, type, mode, extzv_optab,
183 extzvmisalign_optab, 3);
185 default:
186 gcc_unreachable ();
190 /* Return true if an instruction exists to access a field of mode
191 FIELDMODE in a structure that has STRUCT_BITS significant bits.
192 Describe the "best" such instruction in *INSN if so. PATTERN and
193 TYPE describe the type of insertion or extraction we want to perform.
195 For an insertion, the number of significant structure bits includes
196 all bits of the target. For an extraction, it need only include the
197 most significant bit of the field. Larger widths are acceptable
198 in both cases. */
200 static bool
201 get_best_extraction_insn (extraction_insn *insn,
202 enum extraction_pattern pattern,
203 enum extraction_type type,
204 unsigned HOST_WIDE_INT struct_bits,
205 machine_mode field_mode)
207 opt_scalar_int_mode mode_iter;
209 FOR_EACH_MODE_FROM (mode_iter, smallest_int_mode_for_size (struct_bits))
211 scalar_int_mode mode = mode_iter.require ();
212 if (get_extraction_insn (insn, pattern, type, mode))
214 FOR_EACH_MODE_FROM (mode_iter, mode)
216 mode = mode_iter.require ();
217 if (maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (field_mode))
218 || TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
219 field_mode))
220 break;
221 get_extraction_insn (insn, pattern, type, mode);
223 return true;
226 return false;
229 /* Return true if an instruction exists to access a field of mode
230 FIELDMODE in a register structure that has STRUCT_BITS significant bits.
231 Describe the "best" such instruction in *INSN if so. PATTERN describes
232 the type of insertion or extraction we want to perform.
234 For an insertion, the number of significant structure bits includes
235 all bits of the target. For an extraction, it need only include the
236 most significant bit of the field. Larger widths are acceptable
237 in both cases. */
239 bool
240 get_best_reg_extraction_insn (extraction_insn *insn,
241 enum extraction_pattern pattern,
242 unsigned HOST_WIDE_INT struct_bits,
243 machine_mode field_mode)
245 return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
246 field_mode);
249 /* Return true if an instruction exists to access a field of BITSIZE
250 bits starting BITNUM bits into a memory structure. Describe the
251 "best" such instruction in *INSN if so. PATTERN describes the type
252 of insertion or extraction we want to perform and FIELDMODE is the
253 natural mode of the extracted field.
255 The instructions considered here only access bytes that overlap
256 the bitfield; they do not touch any surrounding bytes. */
258 bool
259 get_best_mem_extraction_insn (extraction_insn *insn,
260 enum extraction_pattern pattern,
261 HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
262 machine_mode field_mode)
264 unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
265 + bitsize
266 + BITS_PER_UNIT - 1);
267 struct_bits -= struct_bits % BITS_PER_UNIT;
268 return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
269 struct_bits, field_mode);
272 /* Return the insn code used to extend FROM_MODE to TO_MODE.
273 UNSIGNEDP specifies zero-extension instead of sign-extension. If
274 no such operation exists, CODE_FOR_nothing will be returned. */
276 enum insn_code
277 can_extend_p (machine_mode to_mode, machine_mode from_mode,
278 int unsignedp)
280 if (unsignedp < 0 && targetm.have_ptr_extend ())
281 return targetm.code_for_ptr_extend;
283 convert_optab tab = unsignedp ? zext_optab : sext_optab;
284 return convert_optab_handler (tab, to_mode, from_mode);
287 /* Return the insn code to convert fixed-point mode FIXMODE to floating-point
288 mode FLTMODE, or CODE_FOR_nothing if no such instruction exists.
289 UNSIGNEDP specifies whether FIXMODE is unsigned. */
291 enum insn_code
292 can_float_p (machine_mode fltmode, machine_mode fixmode,
293 int unsignedp)
295 convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
296 return convert_optab_handler (tab, fltmode, fixmode);
299 /* Return the insn code to convert floating-point mode FLTMODE to fixed-point
300 mode FIXMODE, or CODE_FOR_nothing if no such instruction exists.
301 UNSIGNEDP specifies whether FIXMODE is unsigned.
303 On a successful return, set *TRUNCP_PTR to true if it is necessary to
304 output an explicit FTRUNC before the instruction. */
306 enum insn_code
307 can_fix_p (machine_mode fixmode, machine_mode fltmode,
308 int unsignedp, bool *truncp_ptr)
310 convert_optab tab;
311 enum insn_code icode;
313 tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
314 icode = convert_optab_handler (tab, fixmode, fltmode);
315 if (icode != CODE_FOR_nothing)
317 *truncp_ptr = false;
318 return icode;
321 /* FIXME: This requires a port to define both FIX and FTRUNC pattern
322 for this to work. We need to rework the fix* and ftrunc* patterns
323 and documentation. */
324 tab = unsignedp ? ufix_optab : sfix_optab;
325 icode = convert_optab_handler (tab, fixmode, fltmode);
326 if (icode != CODE_FOR_nothing
327 && optab_handler (ftrunc_optab, fltmode) != CODE_FOR_nothing)
329 *truncp_ptr = true;
330 return icode;
333 return CODE_FOR_nothing;
336 /* Return nonzero if a conditional move of mode MODE is supported.
338 This function is for combine so it can tell whether an insn that looks
339 like a conditional move is actually supported by the hardware. If we
340 guess wrong we lose a bit on optimization, but that's it. */
341 /* ??? sparc64 supports conditionally moving integers values based on fp
342 comparisons, and vice versa. How do we handle them? */
344 bool
345 can_conditionally_move_p (machine_mode mode)
347 return direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing;
350 /* If a target doesn't implement a permute on a vector with multibyte
351 elements, we can try to do the same permute on byte elements.
352 If this makes sense for vector mode MODE then return the appropriate
353 byte vector mode. */
355 opt_machine_mode
356 qimode_for_vec_perm (machine_mode mode)
358 if (GET_MODE_INNER (mode) != QImode)
359 return related_vector_mode (mode, QImode, GET_MODE_SIZE (mode));
360 return opt_machine_mode ();
363 /* Return true if selector SEL can be represented in the integer
364 equivalent of vector mode MODE. */
366 bool
367 selector_fits_mode_p (machine_mode mode, const vec_perm_indices &sel)
369 unsigned HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE_INNER (mode));
370 return (mask == HOST_WIDE_INT_M1U
371 || sel.all_in_range_p (0, mask + 1));
374 /* Return true if VEC_PERM_EXPRs with variable selector operands can be
375 expanded using SIMD extensions of the CPU. MODE is the mode of the
376 vectors being permuted. */
378 bool
379 can_vec_perm_var_p (machine_mode mode)
381 /* If the target doesn't implement a vector mode for the vector type,
382 then no operations are supported. */
383 if (!VECTOR_MODE_P (mode))
384 return false;
386 if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
387 return true;
389 /* We allow fallback to a QI vector mode, and adjust the mask. */
390 machine_mode qimode;
391 if (!qimode_for_vec_perm (mode).exists (&qimode)
392 || maybe_gt (GET_MODE_NUNITS (qimode), GET_MODE_MASK (QImode) + 1))
393 return false;
395 if (direct_optab_handler (vec_perm_optab, qimode) == CODE_FOR_nothing)
396 return false;
398 /* In order to support the lowering of variable permutations,
399 we need to support shifts and adds. */
400 if (GET_MODE_UNIT_SIZE (mode) > 2
401 && optab_handler (ashl_optab, mode) == CODE_FOR_nothing
402 && optab_handler (vashl_optab, mode) == CODE_FOR_nothing)
403 return false;
404 if (optab_handler (add_optab, qimode) == CODE_FOR_nothing)
405 return false;
407 return true;
410 /* Return true if the target directly supports VEC_PERM_EXPRs on vectors
411 of mode OP_MODE and result vector of mode MODE using the selector SEL.
412 ALLOW_VARIABLE_P is true if it is acceptable to force the selector into a
413 register and use a variable permute (if the target supports that).
415 Note that additional permutations representing whole-vector shifts may
416 also be handled via the vec_shr or vec_shl optab, but only where the
417 second input vector is entirely constant zeroes; this case is not dealt
418 with here. */
420 bool
421 can_vec_perm_const_p (machine_mode mode, machine_mode op_mode,
422 const vec_perm_indices &sel, bool allow_variable_p)
424 /* If the target doesn't implement a vector mode for the vector type,
425 then no operations are supported. */
426 if (!VECTOR_MODE_P (mode))
427 return false;
429 /* It's probably cheaper to test for the variable case first. */
430 if (op_mode == mode && allow_variable_p && selector_fits_mode_p (mode, sel))
432 if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
433 return true;
435 /* Unlike can_vec_perm_var_p, we don't need to test for optabs
436 related computing the QImode selector, since that happens at
437 compile time. */
438 machine_mode qimode;
439 if (qimode_for_vec_perm (mode).exists (&qimode))
441 vec_perm_indices qimode_indices;
442 qimode_indices.new_expanded_vector (sel, GET_MODE_UNIT_SIZE (mode));
443 if (selector_fits_mode_p (qimode, qimode_indices)
444 && (direct_optab_handler (vec_perm_optab, qimode)
445 != CODE_FOR_nothing))
446 return true;
450 if (targetm.vectorize.vec_perm_const != NULL)
452 if (targetm.vectorize.vec_perm_const (mode, op_mode, NULL_RTX, NULL_RTX,
453 NULL_RTX, sel))
454 return true;
456 /* ??? For completeness, we ought to check the QImode version of
457 vec_perm_const_optab. But all users of this implicit lowering
458 feature implement the variable vec_perm_optab, and the ia64
459 port specifically doesn't want us to lower V2SF operations
460 into integer operations. */
463 return false;
466 /* Find a widening optab even if it doesn't widen as much as we want.
467 E.g. if from_mode is HImode, and to_mode is DImode, and there is no
468 direct HI->SI insn, then return SI->DI, if that exists. */
470 enum insn_code
471 find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
472 machine_mode from_mode,
473 machine_mode *found_mode)
475 machine_mode limit_mode = to_mode;
476 if (is_a <scalar_int_mode> (from_mode))
478 gcc_checking_assert (is_a <scalar_int_mode> (to_mode)
479 && known_lt (GET_MODE_PRECISION (from_mode),
480 GET_MODE_PRECISION (to_mode)));
481 /* The modes after FROM_MODE are all MODE_INT, so the only
482 MODE_PARTIAL_INT mode we consider is FROM_MODE itself.
483 If LIMIT_MODE is MODE_PARTIAL_INT, stop at the containing
484 MODE_INT. */
485 if (GET_MODE_CLASS (limit_mode) == MODE_PARTIAL_INT)
486 limit_mode = GET_MODE_WIDER_MODE (limit_mode).require ();
488 else if (is_a <scalar_int_mode> (to_mode))
490 gcc_checking_assert (VECTOR_MODE_P (from_mode)
491 && GET_MODE_INNER (from_mode) < to_mode);
492 limit_mode = from_mode;
494 else
495 gcc_checking_assert (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
496 && from_mode < to_mode);
497 FOR_EACH_MODE (from_mode, from_mode, limit_mode)
499 enum insn_code handler = convert_optab_handler (op, to_mode, from_mode);
501 if (handler != CODE_FOR_nothing)
503 if (found_mode)
504 *found_mode = from_mode;
505 return handler;
509 return CODE_FOR_nothing;
512 /* Return non-zero if a highpart multiply is supported or can be synthesized.
513 For the benefit of expand_mult_highpart, the return value is 1 for direct,
514 2 for integral widening, 3 for even/odd widening, 4 for hi/lo widening. */
517 can_mult_highpart_p (machine_mode mode, bool uns_p)
519 optab op;
520 scalar_int_mode int_mode, wider_mode;
522 op = uns_p ? umul_highpart_optab : smul_highpart_optab;
523 if (optab_handler (op, mode) != CODE_FOR_nothing)
524 return 1;
526 /* If the mode is integral, synth from widening or larger operations. */
527 if (is_a <scalar_int_mode> (mode, &int_mode)
528 && GET_MODE_WIDER_MODE (int_mode).exists (&wider_mode))
530 op = uns_p ? umul_widen_optab : smul_widen_optab;
531 if (convert_optab_handler (op, wider_mode, mode) != CODE_FOR_nothing)
532 return 2;
534 /* The test on the size comes from expmed_mult_highpart_optab. */
535 if (optab_handler (smul_optab, wider_mode) != CODE_FOR_nothing
536 && GET_MODE_BITSIZE (int_mode) - 1 < BITS_PER_WORD)
537 return 2;
540 /* If the mode is an integral vector, synth from widening operations. */
541 if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
542 return 0;
544 poly_int64 nunits = GET_MODE_NUNITS (mode);
546 op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
547 if (optab_handler (op, mode) != CODE_FOR_nothing)
549 op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
550 if (optab_handler (op, mode) != CODE_FOR_nothing)
552 /* The encoding has 2 interleaved stepped patterns. */
553 vec_perm_builder sel (nunits, 2, 3);
554 for (unsigned int i = 0; i < 6; ++i)
555 sel.quick_push (!BYTES_BIG_ENDIAN
556 + (i & ~1)
557 + ((i & 1) ? nunits : 0));
558 vec_perm_indices indices (sel, 2, nunits);
559 if (can_vec_perm_const_p (mode, mode, indices))
560 return 3;
564 op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
565 if (optab_handler (op, mode) != CODE_FOR_nothing)
567 op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
568 if (optab_handler (op, mode) != CODE_FOR_nothing)
570 /* The encoding has a single stepped pattern. */
571 vec_perm_builder sel (nunits, 1, 3);
572 for (unsigned int i = 0; i < 3; ++i)
573 sel.quick_push (2 * i + (BYTES_BIG_ENDIAN ? 0 : 1));
574 vec_perm_indices indices (sel, 2, nunits);
575 if (can_vec_perm_const_p (mode, mode, indices))
576 return 4;
580 return 0;
583 /* Return true if there is a compare_and_swap pattern. */
585 bool
586 can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
588 enum insn_code icode;
590 /* Check for __atomic_compare_and_swap. */
591 icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
592 if (icode != CODE_FOR_nothing)
593 return true;
595 /* Check for __sync_compare_and_swap. */
596 icode = optab_handler (sync_compare_and_swap_optab, mode);
597 if (icode != CODE_FOR_nothing)
598 return true;
599 if (allow_libcall && optab_libfunc (sync_compare_and_swap_optab, mode))
600 return true;
602 /* No inline compare and swap. */
603 return false;
606 /* Return true if an atomic exchange can be performed. */
608 bool
609 can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
611 enum insn_code icode;
613 /* Check for __atomic_exchange. */
614 icode = direct_optab_handler (atomic_exchange_optab, mode);
615 if (icode != CODE_FOR_nothing)
616 return true;
618 /* Don't check __sync_test_and_set, as on some platforms that
619 has reduced functionality. Targets that really do support
620 a proper exchange should simply be updated to the __atomics. */
622 return can_compare_and_swap_p (mode, allow_libcall);
625 /* Return true if an atomic load can be performed without falling back to
626 a compare-and-swap. */
628 bool
629 can_atomic_load_p (machine_mode mode)
631 enum insn_code icode;
633 /* Does the target supports the load directly? */
634 icode = direct_optab_handler (atomic_load_optab, mode);
635 if (icode != CODE_FOR_nothing)
636 return true;
638 /* If the size of the object is greater than word size on this target,
639 then we assume that a load will not be atomic. Also see
640 expand_atomic_load. */
641 return known_le (GET_MODE_PRECISION (mode), BITS_PER_WORD);
644 /* Determine whether "1 << x" is relatively cheap in word_mode. */
646 bool
647 lshift_cheap_p (bool speed_p)
649 /* FIXME: This should be made target dependent via this "this_target"
650 mechanism, similar to e.g. can_copy_init_p in gcse.cc. */
651 static bool init[2] = { false, false };
652 static bool cheap[2] = { true, true };
654 /* If the targer has no lshift in word_mode, the operation will most
655 probably not be cheap. ??? Does GCC even work for such targets? */
656 if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
657 return false;
659 if (!init[speed_p])
661 rtx reg = gen_raw_REG (word_mode, 10000);
662 int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
663 word_mode, speed_p);
664 cheap[speed_p] = cost < COSTS_N_INSNS (3);
665 init[speed_p] = true;
668 return cheap[speed_p];
671 /* If MODE is not VOIDmode, return true if vector conversion optab OP supports
672 that mode, given that the second mode is always an integer vector.
673 If MODE is VOIDmode, return true if OP supports any vector mode. */
675 static bool
676 supports_vec_convert_optab_p (optab op, machine_mode mode)
678 int start = mode == VOIDmode ? 0 : mode;
679 int end = mode == VOIDmode ? MAX_MACHINE_MODE - 1 : mode;
680 for (int i = start; i <= end; ++i)
681 if (VECTOR_MODE_P ((machine_mode) i))
682 for (int j = MIN_MODE_VECTOR_INT; j < MAX_MODE_VECTOR_INT; ++j)
683 if (convert_optab_handler (op, (machine_mode) i,
684 (machine_mode) j) != CODE_FOR_nothing)
685 return true;
687 return false;
690 /* If MODE is not VOIDmode, return true if vec_gather_load is available for
691 that mode. If MODE is VOIDmode, return true if gather_load is available
692 for at least one vector mode. */
694 bool
695 supports_vec_gather_load_p (machine_mode mode)
697 if (!this_fn_optabs->supports_vec_gather_load[mode])
698 this_fn_optabs->supports_vec_gather_load[mode]
699 = (supports_vec_convert_optab_p (gather_load_optab, mode)
700 || supports_vec_convert_optab_p (mask_gather_load_optab, mode)
701 || supports_vec_convert_optab_p (mask_len_gather_load_optab, mode)
702 ? 1 : -1);
704 return this_fn_optabs->supports_vec_gather_load[mode] > 0;
707 /* If MODE is not VOIDmode, return true if vec_scatter_store is available for
708 that mode. If MODE is VOIDmode, return true if scatter_store is available
709 for at least one vector mode. */
711 bool
712 supports_vec_scatter_store_p (machine_mode mode)
714 if (!this_fn_optabs->supports_vec_scatter_store[mode])
715 this_fn_optabs->supports_vec_scatter_store[mode]
716 = (supports_vec_convert_optab_p (scatter_store_optab, mode)
717 || supports_vec_convert_optab_p (mask_scatter_store_optab, mode)
718 || supports_vec_convert_optab_p (mask_len_scatter_store_optab, mode)
719 ? 1 : -1);
721 return this_fn_optabs->supports_vec_scatter_store[mode] > 0;
724 /* Whether we can extract part of the vector mode MODE as
725 (scalar or vector) mode EXTR_MODE. */
727 bool
728 can_vec_extract (machine_mode mode, machine_mode extr_mode)
730 unsigned m;
731 if (!VECTOR_MODE_P (mode)
732 || !constant_multiple_p (GET_MODE_SIZE (mode),
733 GET_MODE_SIZE (extr_mode), &m))
734 return false;
736 if (convert_optab_handler (vec_extract_optab, mode, extr_mode)
737 != CODE_FOR_nothing)
738 return true;
740 /* Besides a direct vec_extract we can also use an element extract from
741 an integer vector mode with elements of the size of the extr_mode. */
742 scalar_int_mode imode;
743 machine_mode vmode;
744 if (!int_mode_for_size (GET_MODE_BITSIZE (extr_mode), 0).exists (&imode)
745 || !related_vector_mode (mode, imode, m).exists (&vmode)
746 || (convert_optab_handler (vec_extract_optab, vmode, imode)
747 == CODE_FOR_nothing))
748 return false;
749 /* We assume we can pun mode to vmode and imode to extr_mode. */
750 return true;