1 /* IR-agnostic target query functions relating to optabs
2 Copyright (C) 1987-2023 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"
26 #include "optabs-query.h"
27 #include "optabs-libfuncs.h"
28 #include "insn-config.h"
31 #include "vec-perm-indices.h"
33 struct target_optabs default_target_optabs
;
34 struct target_optabs
*this_fn_optabs
= &default_target_optabs
;
36 struct target_optabs
*this_target_optabs
= &default_target_optabs
;
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. */
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
;
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. */
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
;
69 /* Enumerates the possible types of structure operand to an
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). */
81 get_traditional_extraction_insn (extraction_insn
*insn
,
82 enum extraction_type type
,
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
)
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
;
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 ();
110 insn
->struct_mode
= as_a
<scalar_int_mode
> (struct_mode
);
111 insn
->pos_mode
= as_a
<scalar_int_mode
> (pos_mode
);
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. */
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
)
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
;
140 insn
->field_mode
= as_a
<scalar_int_mode
> (mode
);
141 if (type
== ET_unaligned_mem
)
142 insn
->struct_mode
= opt_scalar_int_mode ();
144 insn
->struct_mode
= insn
->field_mode
;
145 insn
->pos_mode
= as_a
<scalar_int_mode
> (pos_mode
);
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. */
154 get_extraction_insn (extraction_insn
*insn
,
155 enum extraction_pattern pattern
,
156 enum extraction_type type
,
162 if (targetm
.have_insv ()
163 && get_traditional_extraction_insn (insn
, type
, mode
,
164 targetm
.code_for_insv
, 0, 3))
166 return get_optab_extraction_insn (insn
, type
, mode
, insv_optab
,
167 insvmisalign_optab
, 2);
170 if (targetm
.have_extv ()
171 && get_traditional_extraction_insn (insn
, type
, mode
,
172 targetm
.code_for_extv
, 1, 0))
174 return get_optab_extraction_insn (insn
, type
, mode
, extv_optab
,
175 extvmisalign_optab
, 3);
178 if (targetm
.have_extzv ()
179 && get_traditional_extraction_insn (insn
, type
, mode
,
180 targetm
.code_for_extzv
, 1, 0))
182 return get_optab_extraction_insn (insn
, type
, mode
, extzv_optab
,
183 extzvmisalign_optab
, 3);
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
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
;
208 FOR_EACH_MODE_FROM (mode_iter
, smallest_int_mode_for_size (struct_bits
))
210 scalar_int_mode mode
= mode_iter
.require ();
211 if (get_extraction_insn (insn
, pattern
, type
, mode
))
213 FOR_EACH_MODE_FROM (mode_iter
, mode
)
215 mode
= mode_iter
.require ();
216 if (maybe_gt (GET_MODE_SIZE (mode
), GET_MODE_SIZE (field_mode
))
217 || TRULY_NOOP_TRUNCATION_MODES_P (insn
->field_mode
,
220 get_extraction_insn (insn
, pattern
, type
, mode
);
228 /* Return true if an instruction exists to access a field of mode
229 FIELDMODE in a register structure that has STRUCT_BITS significant bits.
230 Describe the "best" such instruction in *INSN if so. PATTERN describes
231 the type of insertion or extraction we want to perform.
233 For an insertion, the number of significant structure bits includes
234 all bits of the target. For an extraction, it need only include the
235 most significant bit of the field. Larger widths are acceptable
239 get_best_reg_extraction_insn (extraction_insn
*insn
,
240 enum extraction_pattern pattern
,
241 unsigned HOST_WIDE_INT struct_bits
,
242 machine_mode field_mode
)
244 return get_best_extraction_insn (insn
, pattern
, ET_reg
, struct_bits
,
248 /* Return true if an instruction exists to access a field of BITSIZE
249 bits starting BITNUM bits into a memory structure. Describe the
250 "best" such instruction in *INSN if so. PATTERN describes the type
251 of insertion or extraction we want to perform and FIELDMODE is the
252 natural mode of the extracted field.
254 The instructions considered here only access bytes that overlap
255 the bitfield; they do not touch any surrounding bytes. */
258 get_best_mem_extraction_insn (extraction_insn
*insn
,
259 enum extraction_pattern pattern
,
260 HOST_WIDE_INT bitsize
, HOST_WIDE_INT bitnum
,
261 machine_mode field_mode
)
263 unsigned HOST_WIDE_INT struct_bits
= (bitnum
% BITS_PER_UNIT
265 + BITS_PER_UNIT
- 1);
266 struct_bits
-= struct_bits
% BITS_PER_UNIT
;
267 return get_best_extraction_insn (insn
, pattern
, ET_unaligned_mem
,
268 struct_bits
, field_mode
);
271 /* Return the insn code used to extend FROM_MODE to TO_MODE.
272 UNSIGNEDP specifies zero-extension instead of sign-extension. If
273 no such operation exists, CODE_FOR_nothing will be returned. */
276 can_extend_p (machine_mode to_mode
, machine_mode from_mode
,
279 if (unsignedp
< 0 && targetm
.have_ptr_extend ())
280 return targetm
.code_for_ptr_extend
;
282 convert_optab tab
= unsignedp
? zext_optab
: sext_optab
;
283 return convert_optab_handler (tab
, to_mode
, from_mode
);
286 /* Return the insn code to convert fixed-point mode FIXMODE to floating-point
287 mode FLTMODE, or CODE_FOR_nothing if no such instruction exists.
288 UNSIGNEDP specifies whether FIXMODE is unsigned. */
291 can_float_p (machine_mode fltmode
, machine_mode fixmode
,
294 convert_optab tab
= unsignedp
? ufloat_optab
: sfloat_optab
;
295 return convert_optab_handler (tab
, fltmode
, fixmode
);
298 /* Return the insn code to convert floating-point mode FLTMODE to fixed-point
299 mode FIXMODE, or CODE_FOR_nothing if no such instruction exists.
300 UNSIGNEDP specifies whether FIXMODE is unsigned.
302 On a successful return, set *TRUNCP_PTR to true if it is necessary to
303 output an explicit FTRUNC before the instruction. */
306 can_fix_p (machine_mode fixmode
, machine_mode fltmode
,
307 int unsignedp
, bool *truncp_ptr
)
310 enum insn_code icode
;
312 tab
= unsignedp
? ufixtrunc_optab
: sfixtrunc_optab
;
313 icode
= convert_optab_handler (tab
, fixmode
, fltmode
);
314 if (icode
!= CODE_FOR_nothing
)
320 /* FIXME: This requires a port to define both FIX and FTRUNC pattern
321 for this to work. We need to rework the fix* and ftrunc* patterns
322 and documentation. */
323 tab
= unsignedp
? ufix_optab
: sfix_optab
;
324 icode
= convert_optab_handler (tab
, fixmode
, fltmode
);
325 if (icode
!= CODE_FOR_nothing
326 && optab_handler (ftrunc_optab
, fltmode
) != CODE_FOR_nothing
)
332 return CODE_FOR_nothing
;
335 /* Return nonzero if a conditional move of mode MODE is supported.
337 This function is for combine so it can tell whether an insn that looks
338 like a conditional move is actually supported by the hardware. If we
339 guess wrong we lose a bit on optimization, but that's it. */
340 /* ??? sparc64 supports conditionally moving integers values based on fp
341 comparisons, and vice versa. How do we handle them? */
344 can_conditionally_move_p (machine_mode mode
)
346 return direct_optab_handler (movcc_optab
, mode
) != CODE_FOR_nothing
;
349 /* If a target doesn't implement a permute on a vector with multibyte
350 elements, we can try to do the same permute on byte elements.
351 If this makes sense for vector mode MODE then return the appropriate
355 qimode_for_vec_perm (machine_mode mode
)
357 if (GET_MODE_INNER (mode
) != QImode
)
358 return related_vector_mode (mode
, QImode
, GET_MODE_SIZE (mode
));
359 return opt_machine_mode ();
362 /* Return true if selector SEL can be represented in the integer
363 equivalent of vector mode MODE. */
366 selector_fits_mode_p (machine_mode mode
, const vec_perm_indices
&sel
)
368 unsigned HOST_WIDE_INT mask
= GET_MODE_MASK (GET_MODE_INNER (mode
));
369 return (mask
== HOST_WIDE_INT_M1U
370 || sel
.all_in_range_p (0, mask
+ 1));
373 /* Return true if VEC_PERM_EXPRs with variable selector operands can be
374 expanded using SIMD extensions of the CPU. MODE is the mode of the
375 vectors being permuted. */
378 can_vec_perm_var_p (machine_mode mode
)
380 /* If the target doesn't implement a vector mode for the vector type,
381 then no operations are supported. */
382 if (!VECTOR_MODE_P (mode
))
385 if (direct_optab_handler (vec_perm_optab
, mode
) != CODE_FOR_nothing
)
388 /* We allow fallback to a QI vector mode, and adjust the mask. */
390 if (!qimode_for_vec_perm (mode
).exists (&qimode
)
391 || maybe_gt (GET_MODE_NUNITS (qimode
), GET_MODE_MASK (QImode
) + 1))
394 if (direct_optab_handler (vec_perm_optab
, qimode
) == CODE_FOR_nothing
)
397 /* In order to support the lowering of variable permutations,
398 we need to support shifts and adds. */
399 if (GET_MODE_UNIT_SIZE (mode
) > 2
400 && optab_handler (ashl_optab
, mode
) == CODE_FOR_nothing
401 && optab_handler (vashl_optab
, mode
) == CODE_FOR_nothing
)
403 if (optab_handler (add_optab
, qimode
) == CODE_FOR_nothing
)
409 /* Return true if the target directly supports VEC_PERM_EXPRs on vectors
410 of mode OP_MODE and result vector of mode MODE using the selector SEL.
411 ALLOW_VARIABLE_P is true if it is acceptable to force the selector into a
412 register and use a variable permute (if the target supports that).
414 Note that additional permutations representing whole-vector shifts may
415 also be handled via the vec_shr or vec_shl optab, but only where the
416 second input vector is entirely constant zeroes; this case is not dealt
420 can_vec_perm_const_p (machine_mode mode
, machine_mode op_mode
,
421 const vec_perm_indices
&sel
, bool allow_variable_p
)
423 /* If the target doesn't implement a vector mode for the vector type,
424 then no operations are supported. */
425 if (!VECTOR_MODE_P (mode
))
428 /* It's probably cheaper to test for the variable case first. */
429 if (op_mode
== mode
&& allow_variable_p
&& selector_fits_mode_p (mode
, sel
))
431 if (direct_optab_handler (vec_perm_optab
, mode
) != CODE_FOR_nothing
)
434 /* Unlike can_vec_perm_var_p, we don't need to test for optabs
435 related computing the QImode selector, since that happens at
438 if (qimode_for_vec_perm (mode
).exists (&qimode
))
440 vec_perm_indices qimode_indices
;
441 qimode_indices
.new_expanded_vector (sel
, GET_MODE_UNIT_SIZE (mode
));
442 if (selector_fits_mode_p (qimode
, qimode_indices
)
443 && (direct_optab_handler (vec_perm_optab
, qimode
)
444 != CODE_FOR_nothing
))
449 if (targetm
.vectorize
.vec_perm_const
!= NULL
)
451 if (targetm
.vectorize
.vec_perm_const (mode
, op_mode
, NULL_RTX
, NULL_RTX
,
455 /* ??? For completeness, we ought to check the QImode version of
456 vec_perm_const_optab. But all users of this implicit lowering
457 feature implement the variable vec_perm_optab, and the ia64
458 port specifically doesn't want us to lower V2SF operations
459 into integer operations. */
465 /* Find a widening optab even if it doesn't widen as much as we want.
466 E.g. if from_mode is HImode, and to_mode is DImode, and there is no
467 direct HI->SI insn, then return SI->DI, if that exists. */
470 find_widening_optab_handler_and_mode (optab op
, machine_mode to_mode
,
471 machine_mode from_mode
,
472 machine_mode
*found_mode
)
474 machine_mode limit_mode
= to_mode
;
475 if (is_a
<scalar_int_mode
> (from_mode
))
477 gcc_checking_assert (is_a
<scalar_int_mode
> (to_mode
)
478 && known_lt (GET_MODE_PRECISION (from_mode
),
479 GET_MODE_PRECISION (to_mode
)));
480 /* The modes after FROM_MODE are all MODE_INT, so the only
481 MODE_PARTIAL_INT mode we consider is FROM_MODE itself.
482 If LIMIT_MODE is MODE_PARTIAL_INT, stop at the containing
484 if (GET_MODE_CLASS (limit_mode
) == MODE_PARTIAL_INT
)
485 limit_mode
= GET_MODE_WIDER_MODE (limit_mode
).require ();
488 gcc_checking_assert (GET_MODE_CLASS (from_mode
) == GET_MODE_CLASS (to_mode
)
489 && from_mode
< to_mode
);
490 FOR_EACH_MODE (from_mode
, from_mode
, limit_mode
)
492 enum insn_code handler
= convert_optab_handler (op
, to_mode
, from_mode
);
494 if (handler
!= CODE_FOR_nothing
)
497 *found_mode
= from_mode
;
502 return CODE_FOR_nothing
;
505 /* Return non-zero if a highpart multiply is supported of can be synthisized.
506 For the benefit of expand_mult_highpart, the return value is 1 for direct,
507 2 for even/odd widening, and 3 for hi/lo widening. */
510 can_mult_highpart_p (machine_mode mode
, bool uns_p
)
514 op
= uns_p
? umul_highpart_optab
: smul_highpart_optab
;
515 if (optab_handler (op
, mode
) != CODE_FOR_nothing
)
518 /* If the mode is an integral vector, synth from widening operations. */
519 if (GET_MODE_CLASS (mode
) != MODE_VECTOR_INT
)
522 poly_int64 nunits
= GET_MODE_NUNITS (mode
);
524 op
= uns_p
? vec_widen_umult_even_optab
: vec_widen_smult_even_optab
;
525 if (optab_handler (op
, mode
) != CODE_FOR_nothing
)
527 op
= uns_p
? vec_widen_umult_odd_optab
: vec_widen_smult_odd_optab
;
528 if (optab_handler (op
, mode
) != CODE_FOR_nothing
)
530 /* The encoding has 2 interleaved stepped patterns. */
531 vec_perm_builder
sel (nunits
, 2, 3);
532 for (unsigned int i
= 0; i
< 6; ++i
)
533 sel
.quick_push (!BYTES_BIG_ENDIAN
535 + ((i
& 1) ? nunits
: 0));
536 vec_perm_indices
indices (sel
, 2, nunits
);
537 if (can_vec_perm_const_p (mode
, mode
, indices
))
542 op
= uns_p
? vec_widen_umult_hi_optab
: vec_widen_smult_hi_optab
;
543 if (optab_handler (op
, mode
) != CODE_FOR_nothing
)
545 op
= uns_p
? vec_widen_umult_lo_optab
: vec_widen_smult_lo_optab
;
546 if (optab_handler (op
, mode
) != CODE_FOR_nothing
)
548 /* The encoding has a single stepped pattern. */
549 vec_perm_builder
sel (nunits
, 1, 3);
550 for (unsigned int i
= 0; i
< 3; ++i
)
551 sel
.quick_push (2 * i
+ (BYTES_BIG_ENDIAN
? 0 : 1));
552 vec_perm_indices
indices (sel
, 2, nunits
);
553 if (can_vec_perm_const_p (mode
, mode
, indices
))
561 /* Return true if there is a compare_and_swap pattern. */
564 can_compare_and_swap_p (machine_mode mode
, bool allow_libcall
)
566 enum insn_code icode
;
568 /* Check for __atomic_compare_and_swap. */
569 icode
= direct_optab_handler (atomic_compare_and_swap_optab
, mode
);
570 if (icode
!= CODE_FOR_nothing
)
573 /* Check for __sync_compare_and_swap. */
574 icode
= optab_handler (sync_compare_and_swap_optab
, mode
);
575 if (icode
!= CODE_FOR_nothing
)
577 if (allow_libcall
&& optab_libfunc (sync_compare_and_swap_optab
, mode
))
580 /* No inline compare and swap. */
584 /* Return true if an atomic exchange can be performed. */
587 can_atomic_exchange_p (machine_mode mode
, bool allow_libcall
)
589 enum insn_code icode
;
591 /* Check for __atomic_exchange. */
592 icode
= direct_optab_handler (atomic_exchange_optab
, mode
);
593 if (icode
!= CODE_FOR_nothing
)
596 /* Don't check __sync_test_and_set, as on some platforms that
597 has reduced functionality. Targets that really do support
598 a proper exchange should simply be updated to the __atomics. */
600 return can_compare_and_swap_p (mode
, allow_libcall
);
603 /* Return true if an atomic load can be performed without falling back to
604 a compare-and-swap. */
607 can_atomic_load_p (machine_mode mode
)
609 enum insn_code icode
;
611 /* Does the target supports the load directly? */
612 icode
= direct_optab_handler (atomic_load_optab
, mode
);
613 if (icode
!= CODE_FOR_nothing
)
616 /* If the size of the object is greater than word size on this target,
617 then we assume that a load will not be atomic. Also see
618 expand_atomic_load. */
619 return known_le (GET_MODE_PRECISION (mode
), BITS_PER_WORD
);
622 /* Determine whether "1 << x" is relatively cheap in word_mode. */
625 lshift_cheap_p (bool speed_p
)
627 /* FIXME: This should be made target dependent via this "this_target"
628 mechanism, similar to e.g. can_copy_init_p in gcse.cc. */
629 static bool init
[2] = { false, false };
630 static bool cheap
[2] = { true, true };
632 /* If the targer has no lshift in word_mode, the operation will most
633 probably not be cheap. ??? Does GCC even work for such targets? */
634 if (optab_handler (ashl_optab
, word_mode
) == CODE_FOR_nothing
)
639 rtx reg
= gen_raw_REG (word_mode
, 10000);
640 int cost
= set_src_cost (gen_rtx_ASHIFT (word_mode
, const1_rtx
, reg
),
642 cheap
[speed_p
] = cost
< COSTS_N_INSNS (3);
643 init
[speed_p
] = true;
646 return cheap
[speed_p
];
649 /* If MODE is not VOIDmode, return true if vector conversion optab OP supports
650 that mode, given that the second mode is always an integer vector.
651 If MODE is VOIDmode, return true if OP supports any vector mode. */
654 supports_vec_convert_optab_p (optab op
, machine_mode mode
)
656 int start
= mode
== VOIDmode
? 0 : mode
;
657 int end
= mode
== VOIDmode
? MAX_MACHINE_MODE
- 1 : mode
;
658 for (int i
= start
; i
<= end
; ++i
)
659 if (VECTOR_MODE_P ((machine_mode
) i
))
660 for (int j
= MIN_MODE_VECTOR_INT
; j
< MAX_MODE_VECTOR_INT
; ++j
)
661 if (convert_optab_handler (op
, (machine_mode
) i
,
662 (machine_mode
) j
) != CODE_FOR_nothing
)
668 /* If MODE is not VOIDmode, return true if vec_gather_load is available for
669 that mode. If MODE is VOIDmode, return true if gather_load is available
670 for at least one vector mode. */
673 supports_vec_gather_load_p (machine_mode mode
)
675 if (!this_fn_optabs
->supports_vec_gather_load
[mode
])
676 this_fn_optabs
->supports_vec_gather_load
[mode
]
677 = (supports_vec_convert_optab_p (gather_load_optab
, mode
)
678 || supports_vec_convert_optab_p (mask_gather_load_optab
, mode
)
679 || supports_vec_convert_optab_p (mask_len_gather_load_optab
, mode
)
682 return this_fn_optabs
->supports_vec_gather_load
[mode
] > 0;
685 /* If MODE is not VOIDmode, return true if vec_scatter_store is available for
686 that mode. If MODE is VOIDmode, return true if scatter_store is available
687 for at least one vector mode. */
690 supports_vec_scatter_store_p (machine_mode mode
)
692 if (!this_fn_optabs
->supports_vec_scatter_store
[mode
])
693 this_fn_optabs
->supports_vec_scatter_store
[mode
]
694 = (supports_vec_convert_optab_p (scatter_store_optab
, mode
)
695 || supports_vec_convert_optab_p (mask_scatter_store_optab
, mode
)
696 || supports_vec_convert_optab_p (mask_len_scatter_store_optab
, mode
)
699 return this_fn_optabs
->supports_vec_scatter_store
[mode
] > 0;
702 /* Whether we can extract part of the vector mode MODE as
703 (scalar or vector) mode EXTR_MODE. */
706 can_vec_extract (machine_mode mode
, machine_mode extr_mode
)
709 if (!VECTOR_MODE_P (mode
)
710 || !constant_multiple_p (GET_MODE_SIZE (mode
),
711 GET_MODE_SIZE (extr_mode
), &m
))
714 if (convert_optab_handler (vec_extract_optab
, mode
, extr_mode
)
718 /* Besides a direct vec_extract we can also use an element extract from
719 an integer vector mode with elements of the size of the extr_mode. */
720 scalar_int_mode imode
;
722 if (!int_mode_for_size (GET_MODE_BITSIZE (extr_mode
), 0).exists (&imode
)
723 || !related_vector_mode (mode
, imode
, m
).exists (&vmode
)
724 || (convert_optab_handler (vec_extract_optab
, vmode
, imode
)
725 == CODE_FOR_nothing
))
727 /* We assume we can pun mode to vmode and imode to extr_mode. */