Line data Source code
1 : /* IR-agnostic target query functions relating to optabs
2 : Copyright (C) 1987-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
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.
10 :
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.
15 :
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/>. */
19 :
20 :
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"
32 : #include "internal-fn.h"
33 : #include "memmodel.h"
34 : #include "optabs.h"
35 :
36 : struct target_optabs default_target_optabs;
37 : struct target_optabs *this_fn_optabs = &default_target_optabs;
38 : #if SWITCHABLE_TARGET
39 : struct target_optabs *this_target_optabs = &default_target_optabs;
40 : #endif
41 :
42 : /* Return the insn used to perform conversion OP from mode FROM_MODE
43 : to mode TO_MODE; return CODE_FOR_nothing if the target does not have
44 : such an insn, or if it is unsuitable for optimization type OPT_TYPE. */
45 :
46 : insn_code
47 87809 : convert_optab_handler (convert_optab optab, machine_mode to_mode,
48 : machine_mode from_mode, optimization_type opt_type)
49 : {
50 87809 : insn_code icode = convert_optab_handler (optab, to_mode, from_mode);
51 87809 : if (icode == CODE_FOR_nothing
52 87809 : || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type))
53 87211 : return CODE_FOR_nothing;
54 : return icode;
55 : }
56 :
57 : /* Return the insn used to implement mode MODE of OP; return
58 : CODE_FOR_nothing if the target does not have such an insn,
59 : or if it is unsuitable for optimization type OPT_TYPE. */
60 :
61 : insn_code
62 4015485 : direct_optab_handler (convert_optab optab, machine_mode mode,
63 : optimization_type opt_type)
64 : {
65 4015485 : insn_code icode = direct_optab_handler (optab, mode);
66 4015485 : if (icode == CODE_FOR_nothing
67 4015485 : || !targetm.optab_supported_p (optab, mode, mode, opt_type))
68 3674532 : return CODE_FOR_nothing;
69 : return icode;
70 : }
71 :
72 : /* Enumerates the possible types of structure operand to an
73 : extraction_insn. */
74 : enum extraction_type { ET_unaligned_mem, ET_reg };
75 :
76 : /* Check whether insv, extv or extzv pattern ICODE can be used for an
77 : insertion or extraction of type TYPE on a structure of mode MODE.
78 : Return true if so and fill in *INSN accordingly. STRUCT_OP is the
79 : operand number of the structure (the first sign_extract or zero_extract
80 : operand) and FIELD_OP is the operand number of the field (the other
81 : side of the set from the sign_extract or zero_extract). */
82 :
83 : static bool
84 0 : get_traditional_extraction_insn (extraction_insn *insn,
85 : enum extraction_type type,
86 : machine_mode mode,
87 : enum insn_code icode,
88 : int struct_op, int field_op)
89 : {
90 0 : const struct insn_data_d *data = &insn_data[icode];
91 :
92 0 : machine_mode struct_mode = data->operand[struct_op].mode;
93 0 : if (struct_mode == VOIDmode)
94 0 : struct_mode = word_mode;
95 0 : if (mode != struct_mode)
96 : return false;
97 :
98 0 : machine_mode field_mode = data->operand[field_op].mode;
99 0 : if (field_mode == VOIDmode)
100 0 : field_mode = word_mode;
101 :
102 0 : machine_mode pos_mode = data->operand[struct_op + 2].mode;
103 0 : if (pos_mode == VOIDmode)
104 0 : pos_mode = word_mode;
105 :
106 0 : insn->icode = icode;
107 0 : insn->field_mode = as_a <scalar_int_mode> (field_mode);
108 0 : if (type == ET_unaligned_mem)
109 0 : insn->struct_mode = byte_mode;
110 0 : else if (struct_mode == BLKmode)
111 0 : insn->struct_mode = opt_scalar_int_mode ();
112 : else
113 0 : insn->struct_mode = as_a <scalar_int_mode> (struct_mode);
114 0 : insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
115 0 : return true;
116 : }
117 :
118 : /* Return true if an optab exists to perform an insertion or extraction
119 : of type TYPE in mode MODE. Describe the instruction in *INSN if so.
120 :
121 : REG_OPTAB is the optab to use for register structures and
122 : MISALIGN_OPTAB is the optab to use for misaligned memory structures.
123 : POS_OP is the operand number of the bit position. */
124 :
125 : static bool
126 3549054 : get_optab_extraction_insn (class extraction_insn *insn,
127 : enum extraction_type type,
128 : machine_mode mode, direct_optab reg_optab,
129 : direct_optab misalign_optab, int pos_op)
130 : {
131 3549054 : direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
132 3549054 : enum insn_code icode = direct_optab_handler (optab, mode);
133 3549054 : if (icode == CODE_FOR_nothing)
134 : return false;
135 :
136 1599077 : const struct insn_data_d *data = &insn_data[icode];
137 :
138 1599077 : machine_mode pos_mode = data->operand[pos_op].mode;
139 1599077 : if (pos_mode == VOIDmode)
140 0 : pos_mode = word_mode;
141 :
142 1599077 : insn->icode = icode;
143 1599077 : insn->field_mode = as_a <scalar_int_mode> (mode);
144 1599077 : if (type == ET_unaligned_mem)
145 0 : insn->struct_mode = opt_scalar_int_mode ();
146 : else
147 1599077 : insn->struct_mode = insn->field_mode;
148 1599077 : insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
149 1599077 : return true;
150 : }
151 :
152 : /* Return true if an instruction exists to perform an insertion or
153 : extraction (PATTERN says which) of type TYPE in mode MODE.
154 : Describe the instruction in *INSN if so. */
155 :
156 : static bool
157 3549054 : get_extraction_insn (extraction_insn *insn,
158 : enum extraction_pattern pattern,
159 : enum extraction_type type,
160 : machine_mode mode)
161 : {
162 3549054 : switch (pattern)
163 : {
164 542880 : case EP_insv:
165 542880 : if (targetm.have_insv ()
166 542880 : && get_traditional_extraction_insn (insn, type, mode,
167 : targetm.code_for_insv, 0, 3))
168 : return true;
169 542880 : return get_optab_extraction_insn (insn, type, mode, insv_optab,
170 542880 : insvmisalign_optab, 2);
171 :
172 753082 : case EP_extv:
173 753082 : if (targetm.have_extv ()
174 753082 : && get_traditional_extraction_insn (insn, type, mode,
175 : targetm.code_for_extv, 1, 0))
176 : return true;
177 753082 : return get_optab_extraction_insn (insn, type, mode, extv_optab,
178 753082 : extvmisalign_optab, 3);
179 :
180 2253092 : case EP_extzv:
181 2253092 : if (targetm.have_extzv ()
182 2253092 : && get_traditional_extraction_insn (insn, type, mode,
183 : targetm.code_for_extzv, 1, 0))
184 : return true;
185 2253092 : return get_optab_extraction_insn (insn, type, mode, extzv_optab,
186 2253092 : extzvmisalign_optab, 3);
187 :
188 0 : default:
189 0 : gcc_unreachable ();
190 : }
191 : }
192 :
193 : /* Return true if an instruction exists to access a field of mode
194 : FIELDMODE in a structure that has STRUCT_BITS significant bits.
195 : Describe the "best" such instruction in *INSN if so. PATTERN and
196 : TYPE describe the type of insertion or extraction we want to perform.
197 :
198 : For an insertion, the number of significant structure bits includes
199 : all bits of the target. For an extraction, it need only include the
200 : most significant bit of the field. Larger widths are acceptable
201 : in both cases. */
202 :
203 : static bool
204 1928011 : get_best_extraction_insn (extraction_insn *insn,
205 : enum extraction_pattern pattern,
206 : enum extraction_type type,
207 : unsigned HOST_WIDE_INT struct_bits,
208 : machine_mode field_mode)
209 : {
210 1928011 : opt_scalar_int_mode mode_iter;
211 :
212 3877988 : FOR_EACH_MODE_FROM (mode_iter, smallest_int_mode_for_size (struct_bits))
213 : {
214 3549054 : scalar_int_mode mode = mode_iter.require ();
215 3549054 : if (get_extraction_insn (insn, pattern, type, mode))
216 : {
217 1599077 : FOR_EACH_MODE_FROM (mode_iter, mode)
218 : {
219 1599077 : mode = mode_iter.require ();
220 3198154 : if (maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (field_mode))
221 1599077 : || TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
222 : field_mode))
223 : break;
224 0 : get_extraction_insn (insn, pattern, type, mode);
225 : }
226 1599077 : return true;
227 : }
228 : }
229 : return false;
230 : }
231 :
232 : /* Return true if an instruction exists to access a field of mode
233 : FIELDMODE in a register structure that has STRUCT_BITS significant bits.
234 : Describe the "best" such instruction in *INSN if so. PATTERN describes
235 : the type of insertion or extraction we want to perform.
236 :
237 : For an insertion, the number of significant structure bits includes
238 : all bits of the target. For an extraction, it need only include the
239 : most significant bit of the field. Larger widths are acceptable
240 : in both cases. */
241 :
242 : bool
243 1721096 : get_best_reg_extraction_insn (extraction_insn *insn,
244 : enum extraction_pattern pattern,
245 : unsigned HOST_WIDE_INT struct_bits,
246 : machine_mode field_mode)
247 : {
248 1721096 : return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
249 1721096 : field_mode);
250 : }
251 :
252 : /* Return true if an instruction exists to access a field of BITSIZE
253 : bits starting BITNUM bits into a memory structure. Describe the
254 : "best" such instruction in *INSN if so. PATTERN describes the type
255 : of insertion or extraction we want to perform and FIELDMODE is the
256 : natural mode of the extracted field.
257 :
258 : The instructions considered here only access bytes that overlap
259 : the bitfield; they do not touch any surrounding bytes. */
260 :
261 : bool
262 206915 : get_best_mem_extraction_insn (extraction_insn *insn,
263 : enum extraction_pattern pattern,
264 : HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
265 : machine_mode field_mode)
266 : {
267 206915 : unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
268 206915 : + bitsize
269 206915 : + BITS_PER_UNIT - 1);
270 206915 : struct_bits -= struct_bits % BITS_PER_UNIT;
271 206915 : return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
272 206915 : struct_bits, field_mode);
273 : }
274 :
275 : /* Return the insn code used to extend FROM_MODE to TO_MODE.
276 : UNSIGNEDP specifies zero-extension instead of sign-extension. If
277 : no such operation exists, CODE_FOR_nothing will be returned. */
278 :
279 : enum insn_code
280 5398147 : can_extend_p (machine_mode to_mode, machine_mode from_mode,
281 : int unsignedp)
282 : {
283 5398147 : if (unsignedp < 0 && targetm.have_ptr_extend ())
284 0 : return targetm.code_for_ptr_extend;
285 :
286 5398147 : convert_optab tab = unsignedp ? zext_optab : sext_optab;
287 5398147 : return convert_optab_handler (tab, to_mode, from_mode);
288 : }
289 :
290 : /* Return the insn code to convert fixed-point mode FIXMODE to floating-point
291 : mode FLTMODE, or CODE_FOR_nothing if no such instruction exists.
292 : UNSIGNEDP specifies whether FIXMODE is unsigned. */
293 :
294 : enum insn_code
295 371389 : can_float_p (machine_mode fltmode, machine_mode fixmode,
296 : int unsignedp)
297 : {
298 371389 : convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
299 371389 : return convert_optab_handler (tab, fltmode, fixmode);
300 : }
301 :
302 : /* Return the insn code to convert floating-point mode FLTMODE to fixed-point
303 : mode FIXMODE, or CODE_FOR_nothing if no such instruction exists.
304 : UNSIGNEDP specifies whether FIXMODE is unsigned.
305 :
306 : On a successful return, set *TRUNCP_PTR to true if it is necessary to
307 : output an explicit FTRUNC before the instruction. */
308 :
309 : enum insn_code
310 252428 : can_fix_p (machine_mode fixmode, machine_mode fltmode,
311 : int unsignedp, bool *truncp_ptr)
312 : {
313 252428 : convert_optab tab;
314 252428 : enum insn_code icode;
315 :
316 252428 : tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
317 252428 : icode = convert_optab_handler (tab, fixmode, fltmode);
318 252428 : if (icode != CODE_FOR_nothing)
319 : {
320 50812 : *truncp_ptr = false;
321 50812 : return icode;
322 : }
323 :
324 : /* FIXME: This requires a port to define both FIX and FTRUNC pattern
325 : for this to work. We need to rework the fix* and ftrunc* patterns
326 : and documentation. */
327 201616 : tab = unsignedp ? ufix_optab : sfix_optab;
328 201616 : icode = convert_optab_handler (tab, fixmode, fltmode);
329 201616 : if (icode != CODE_FOR_nothing
330 201616 : && optab_handler (ftrunc_optab, fltmode) != CODE_FOR_nothing)
331 : {
332 0 : *truncp_ptr = true;
333 0 : return icode;
334 : }
335 :
336 : return CODE_FOR_nothing;
337 : }
338 :
339 : /* Return nonzero if a conditional move of mode MODE is supported.
340 :
341 : This function is for combine so it can tell whether an insn that looks
342 : like a conditional move is actually supported by the hardware. If we
343 : guess wrong we lose a bit on optimization, but that's it. */
344 : /* ??? sparc64 supports conditionally moving integers values based on fp
345 : comparisons, and vice versa. How do we handle them? */
346 :
347 : bool
348 1209666 : can_conditionally_move_p (machine_mode mode)
349 : {
350 1209666 : return direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing;
351 : }
352 :
353 : /* If a target doesn't implement a permute on a vector with multibyte
354 : elements, we can try to do the same permute on byte elements.
355 : If this makes sense for vector mode MODE then return the appropriate
356 : byte vector mode. */
357 :
358 : opt_machine_mode
359 788115 : qimode_for_vec_perm (machine_mode mode)
360 : {
361 788115 : if (GET_MODE_INNER (mode) != QImode
362 1534658 : && multiple_p (GET_MODE_PRECISION (GET_MODE_INNER (mode)),
363 746543 : GET_MODE_PRECISION (QImode)))
364 1493086 : return related_vector_mode (mode, QImode, GET_MODE_SIZE (mode));
365 41572 : return opt_machine_mode ();
366 : }
367 :
368 : /* Return true if selector SEL can be represented in the integer
369 : equivalent of vector mode MODE. */
370 :
371 : bool
372 1526388 : selector_fits_mode_p (machine_mode mode, const vec_perm_indices &sel)
373 : {
374 1526388 : unsigned HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE_INNER (mode));
375 1526388 : return (mask == HOST_WIDE_INT_M1U
376 1526388 : || sel.all_in_range_p (0, mask + 1));
377 : }
378 :
379 : /* Return true if VEC_PERM_EXPRs with variable selector operands can be
380 : expanded using SIMD extensions of the CPU. MODE is the mode of the
381 : vectors being permuted. */
382 :
383 : bool
384 872 : can_vec_perm_var_p (machine_mode mode)
385 : {
386 : /* If the target doesn't implement a vector mode for the vector type,
387 : then no operations are supported. */
388 872 : if (!VECTOR_MODE_P (mode))
389 : return false;
390 :
391 621 : if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
392 : return true;
393 :
394 : /* We allow fallback to a QI vector mode, and adjust the mask. */
395 610 : machine_mode qimode;
396 610 : if (!qimode_for_vec_perm (mode).exists (&qimode)
397 988 : || maybe_gt (GET_MODE_NUNITS (qimode), GET_MODE_MASK (QImode) + 1))
398 116 : return false;
399 :
400 494 : if (direct_optab_handler (vec_perm_optab, qimode) == CODE_FOR_nothing)
401 : return false;
402 :
403 : /* In order to support the lowering of variable permutations,
404 : we need to support shifts and adds. */
405 0 : if (GET_MODE_UNIT_SIZE (mode) > 2
406 0 : && optab_handler (ashl_optab, mode) == CODE_FOR_nothing
407 0 : && optab_handler (vashl_optab, mode) == CODE_FOR_nothing)
408 : return false;
409 0 : if (optab_handler (add_optab, qimode) == CODE_FOR_nothing)
410 : return false;
411 :
412 : return true;
413 : }
414 :
415 : /* Return true if the target directly supports VEC_PERM_EXPRs on vectors
416 : of mode OP_MODE and result vector of mode MODE using the selector SEL.
417 : ALLOW_VARIABLE_P is true if it is acceptable to force the selector into a
418 : register and use a variable permute (if the target supports that).
419 :
420 : Note that additional permutations representing whole-vector shifts may
421 : also be handled via the vec_shr or vec_shl optab, but only where the
422 : second input vector is entirely constant zeroes; this case is not dealt
423 : with here. */
424 :
425 : bool
426 895504 : can_vec_perm_const_p (machine_mode mode, machine_mode op_mode,
427 : const vec_perm_indices &sel, bool allow_variable_p)
428 : {
429 : /* If the target doesn't implement a vector mode for the vector type,
430 : then no operations are supported. */
431 895504 : if (!VECTOR_MODE_P (mode))
432 : return false;
433 :
434 : /* It's probably cheaper to test for the variable case first. */
435 893454 : if (op_mode == mode && allow_variable_p && selector_fits_mode_p (mode, sel))
436 : {
437 848553 : if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
438 895504 : return true;
439 :
440 : /* Unlike can_vec_perm_var_p, we don't need to test for optabs
441 : related computing the QImode selector, since that happens at
442 : compile time. */
443 712269 : machine_mode qimode;
444 712269 : if (qimode_for_vec_perm (mode).exists (&qimode))
445 : {
446 677835 : vec_perm_indices qimode_indices;
447 1355670 : qimode_indices.new_expanded_vector (sel, GET_MODE_UNIT_SIZE (mode));
448 677835 : if (selector_fits_mode_p (qimode, qimode_indices)
449 677835 : && (direct_optab_handler (vec_perm_optab, qimode)
450 : != CODE_FOR_nothing))
451 6 : return true;
452 677835 : }
453 : }
454 :
455 757164 : if (targetm.vectorize.vec_perm_const != NULL)
456 : {
457 757164 : if (targetm.vectorize.vec_perm_const (mode, op_mode, NULL_RTX, NULL_RTX,
458 : NULL_RTX, sel))
459 : return true;
460 :
461 : /* ??? For completeness, we ought to check the QImode version of
462 : vec_perm_const_optab. But all users of this implicit lowering
463 : feature implement the variable vec_perm_optab, and the ia64
464 : port specifically doesn't want us to lower V2SF operations
465 : into integer operations. */
466 : }
467 :
468 : return false;
469 : }
470 :
471 : /* Find a widening optab even if it doesn't widen as much as we want.
472 : E.g. if from_mode is HImode, and to_mode is DImode, and there is no
473 : direct HI->SI insn, then return SI->DI, if that exists. */
474 :
475 : enum insn_code
476 303013 : find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
477 : machine_mode from_mode,
478 : machine_mode *found_mode)
479 : {
480 303013 : machine_mode limit_mode = to_mode;
481 303013 : if (is_a <scalar_int_mode> (from_mode))
482 : {
483 302364 : gcc_checking_assert (is_a <scalar_int_mode> (to_mode)
484 : && known_lt (GET_MODE_PRECISION (from_mode),
485 : GET_MODE_PRECISION (to_mode)));
486 : /* The modes after FROM_MODE are all MODE_INT, so the only
487 : MODE_PARTIAL_INT mode we consider is FROM_MODE itself.
488 : If LIMIT_MODE is MODE_PARTIAL_INT, stop at the containing
489 : MODE_INT. */
490 302364 : if (GET_MODE_CLASS (limit_mode) == MODE_PARTIAL_INT)
491 0 : limit_mode = GET_MODE_WIDER_MODE (limit_mode).require ();
492 : }
493 649 : else if (is_a <scalar_int_mode> (to_mode))
494 : {
495 0 : gcc_checking_assert (VECTOR_MODE_P (from_mode)
496 : && GET_MODE_INNER (from_mode) < to_mode);
497 0 : limit_mode = GET_MODE_NEXT_MODE (from_mode).require ();
498 : }
499 : else
500 649 : gcc_checking_assert (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
501 : && from_mode < to_mode);
502 568772 : FOR_EACH_MODE (from_mode, from_mode, limit_mode)
503 : {
504 326548 : enum insn_code handler = convert_optab_handler (op, to_mode, from_mode);
505 :
506 326548 : if (handler != CODE_FOR_nothing)
507 : {
508 60789 : if (found_mode)
509 10127 : *found_mode = from_mode;
510 60789 : return handler;
511 : }
512 : }
513 :
514 : return CODE_FOR_nothing;
515 : }
516 :
517 : /* Return non-zero if a highpart multiply is supported or can be synthesized.
518 : For the benefit of expand_mult_highpart, the return value is 1 for direct,
519 : 2 for integral widening, 3 for even/odd widening, 4 for hi/lo widening. */
520 :
521 : int
522 79896 : can_mult_highpart_p (machine_mode mode, bool uns_p)
523 : {
524 79896 : optab op;
525 79896 : scalar_int_mode int_mode, wider_mode;
526 :
527 79896 : op = uns_p ? umul_highpart_optab : smul_highpart_optab;
528 79896 : if (optab_handler (op, mode) != CODE_FOR_nothing)
529 : return 1;
530 :
531 : /* If the mode is integral, synth from widening or larger operations. */
532 76858 : if (is_a <scalar_int_mode> (mode, &int_mode)
533 4495 : && GET_MODE_WIDER_MODE (int_mode).exists (&wider_mode))
534 : {
535 4495 : op = uns_p ? umul_widen_optab : smul_widen_optab;
536 4495 : if (convert_optab_handler (op, wider_mode, mode) != CODE_FOR_nothing)
537 : return 2;
538 :
539 : /* The test on the size comes from expmed_mult_highpart_optab. */
540 4495 : if (optab_handler (smul_optab, wider_mode) != CODE_FOR_nothing
541 4495 : && GET_MODE_BITSIZE (int_mode) - 1 < BITS_PER_WORD)
542 : return 2;
543 : }
544 :
545 : /* If the mode is an integral vector, synth from widening operations. */
546 76858 : if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
547 : return 0;
548 :
549 144726 : poly_int64 nunits = GET_MODE_NUNITS (mode);
550 :
551 72363 : op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
552 72363 : if (optab_handler (op, mode) != CODE_FOR_nothing)
553 : {
554 21758 : op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
555 21758 : if (optab_handler (op, mode) != CODE_FOR_nothing)
556 : {
557 : /* The encoding has 2 interleaved stepped patterns. */
558 21758 : vec_perm_builder sel (nunits, 2, 3);
559 152306 : for (unsigned int i = 0; i < 6; ++i)
560 261096 : sel.quick_push (!BYTES_BIG_ENDIAN
561 130548 : + (i & ~1)
562 195822 : + ((i & 1) ? nunits : 0));
563 21758 : vec_perm_indices indices (sel, 2, nunits);
564 21758 : if (can_vec_perm_const_p (mode, mode, indices))
565 21758 : return 3;
566 21758 : }
567 : }
568 :
569 50605 : op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
570 50605 : if (optab_handler (op, mode) != CODE_FOR_nothing)
571 : {
572 274 : op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
573 274 : if (optab_handler (op, mode) != CODE_FOR_nothing)
574 : {
575 : /* The encoding has a single stepped pattern. */
576 274 : vec_perm_builder sel (nunits, 1, 3);
577 1096 : for (unsigned int i = 0; i < 3; ++i)
578 822 : sel.quick_push (2 * i + (BYTES_BIG_ENDIAN ? 0 : 1));
579 274 : vec_perm_indices indices (sel, 2, nunits);
580 274 : if (can_vec_perm_const_p (mode, mode, indices))
581 274 : return 4;
582 274 : }
583 : }
584 :
585 : return 0;
586 : }
587 :
588 : /* Return true if there is a compare_and_swap pattern. */
589 :
590 : bool
591 158620 : can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
592 : {
593 158620 : enum insn_code icode;
594 :
595 : /* Check for __atomic_compare_and_swap. */
596 158620 : icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
597 158620 : if (icode != CODE_FOR_nothing)
598 : return true;
599 :
600 : /* Check for __sync_compare_and_swap. */
601 129 : icode = optab_handler (sync_compare_and_swap_optab, mode);
602 129 : if (icode != CODE_FOR_nothing)
603 : return true;
604 129 : if (allow_libcall && optab_libfunc (sync_compare_and_swap_optab, mode))
605 : return true;
606 :
607 : /* No inline compare and swap. */
608 : return false;
609 : }
610 :
611 : /* Return true if an atomic exchange can be performed. */
612 :
613 : bool
614 88 : can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
615 : {
616 88 : enum insn_code icode;
617 :
618 : /* Check for __atomic_exchange. */
619 88 : icode = direct_optab_handler (atomic_exchange_optab, mode);
620 88 : if (icode != CODE_FOR_nothing)
621 : return true;
622 :
623 : /* Don't check __sync_test_and_set, as on some platforms that
624 : has reduced functionality. Targets that really do support
625 : a proper exchange should simply be updated to the __atomics. */
626 :
627 0 : return can_compare_and_swap_p (mode, allow_libcall);
628 : }
629 :
630 : /* Return true if an atomic load can be performed without falling back to
631 : a compare-and-swap. */
632 :
633 : bool
634 213790 : can_atomic_load_p (machine_mode mode)
635 : {
636 213790 : enum insn_code icode;
637 :
638 : /* Does the target supports the load directly? */
639 213790 : icode = direct_optab_handler (atomic_load_optab, mode);
640 213790 : if (icode != CODE_FOR_nothing)
641 : return true;
642 :
643 : /* If the size of the object is greater than word size on this target,
644 : then we assume that a load will not be atomic. Also see
645 : expand_atomic_load. */
646 4048 : return known_le (GET_MODE_PRECISION (mode), BITS_PER_WORD);
647 : }
648 :
649 : /* Determine whether "1 << x" is relatively cheap in word_mode. */
650 :
651 : bool
652 1063646 : lshift_cheap_p (bool speed_p)
653 : {
654 : /* FIXME: This should be made target dependent via this "this_target"
655 : mechanism, similar to e.g. can_copy_init_p in gcse.cc. */
656 1063646 : static bool init[2] = { false, false };
657 1063646 : static bool cheap[2] = { true, true };
658 :
659 : /* If the targer has no lshift in word_mode, the operation will most
660 : probably not be cheap. ??? Does GCC even work for such targets? */
661 1063646 : if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
662 : return false;
663 :
664 1063646 : if (!init[speed_p])
665 : {
666 41125 : rtx reg = gen_raw_REG (word_mode, 10000);
667 41125 : int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
668 : word_mode, speed_p);
669 41125 : cheap[speed_p] = cost < COSTS_N_INSNS (3);
670 41125 : init[speed_p] = true;
671 : }
672 :
673 1063646 : return cheap[speed_p];
674 : }
675 :
676 : /* If MODE is not VOIDmode, return true if vector conversion optab OP supports
677 : that mode, given that the second mode is always an integer vector.
678 : If MODE is VOIDmode, return true if OP supports any vector mode. */
679 :
680 : static enum insn_code
681 194844 : supported_vec_convert_optab (optab op, machine_mode mode)
682 : {
683 194844 : int start = mode == VOIDmode ? 0 : mode;
684 194844 : int end = mode == VOIDmode ? MAX_MACHINE_MODE - 1 : mode;
685 194844 : enum insn_code icode = CODE_FOR_nothing;
686 389688 : for (int i = start; i <= end; ++i)
687 194844 : if (VECTOR_MODE_P ((machine_mode) i))
688 6040164 : for (int j = MIN_MODE_VECTOR_INT; j < MAX_MODE_VECTOR_INT; ++j)
689 : {
690 11690640 : if ((icode
691 5845320 : = convert_optab_handler (op, (machine_mode) i,
692 : (machine_mode) j)) != CODE_FOR_nothing)
693 : return icode;
694 : }
695 :
696 : return icode;
697 : }
698 :
699 : /* If MODE is not VOIDmode, return true if vec_gather_load is available for
700 : that mode. If MODE is VOIDmode, return true if gather_load is available
701 : for at least one vector mode.
702 : In that case, and if ELSVALS is nonzero, store the supported else values
703 : into the vector it points to. */
704 :
705 : bool
706 275223 : supports_vec_gather_load_p (machine_mode mode, vec<int> *elsvals)
707 : {
708 275223 : enum insn_code icode = CODE_FOR_nothing;
709 275223 : if (!this_fn_optabs->supports_vec_gather_load[mode] || elsvals)
710 : {
711 : /* Try the masked variants first. In case we later decide that we
712 : need a mask after all (thus requiring an else operand) we need
713 : to query it below and we cannot do that when using the
714 : non-masked optab. */
715 57133 : icode = supported_vec_convert_optab (mask_gather_load_optab, mode);
716 57133 : if (icode == CODE_FOR_nothing)
717 57133 : icode = supported_vec_convert_optab (mask_len_gather_load_optab, mode);
718 57133 : if (icode == CODE_FOR_nothing)
719 57133 : icode = supported_vec_convert_optab (gather_load_optab, mode);
720 114266 : this_fn_optabs->supports_vec_gather_load[mode]
721 114266 : = (icode != CODE_FOR_nothing) ? 1 : -1;
722 : }
723 :
724 275223 : if (elsvals && icode != CODE_FOR_nothing)
725 0 : get_supported_else_vals
726 0 : (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
727 :
728 275223 : return this_fn_optabs->supports_vec_gather_load[mode] > 0;
729 : }
730 :
731 : /* If MODE is not VOIDmode, return true if vec_scatter_store is available for
732 : that mode. If MODE is VOIDmode, return true if scatter_store is available
733 : for at least one vector mode. */
734 :
735 : bool
736 96394 : supports_vec_scatter_store_p (machine_mode mode)
737 : {
738 96394 : enum insn_code icode;
739 96394 : if (!this_fn_optabs->supports_vec_scatter_store[mode])
740 : {
741 7815 : icode = supported_vec_convert_optab (scatter_store_optab, mode);
742 7815 : if (icode == CODE_FOR_nothing)
743 7815 : icode = supported_vec_convert_optab (mask_scatter_store_optab, mode);
744 7815 : if (icode == CODE_FOR_nothing)
745 7815 : icode = supported_vec_convert_optab (mask_len_scatter_store_optab,
746 : mode);
747 15630 : this_fn_optabs->supports_vec_scatter_store[mode]
748 7815 : = (icode != CODE_FOR_nothing) ? 1 : -1;
749 : }
750 :
751 96394 : return this_fn_optabs->supports_vec_scatter_store[mode] > 0;
752 : }
753 :
754 : /* Whether we can extract part of the vector mode MODE as
755 : (scalar or vector) mode EXTR_MODE. */
756 :
757 : bool
758 4291 : can_vec_extract (machine_mode mode, machine_mode extr_mode)
759 : {
760 4291 : unsigned m;
761 2478 : if (!VECTOR_MODE_P (mode)
762 8582 : || !constant_multiple_p (GET_MODE_SIZE (mode),
763 4289 : GET_MODE_SIZE (extr_mode), &m))
764 : return false;
765 :
766 4289 : if (convert_optab_handler (vec_extract_optab, mode, extr_mode)
767 : != CODE_FOR_nothing)
768 : return true;
769 :
770 : /* Besides a direct vec_extract we can also use an element extract from
771 : an integer vector mode with elements of the size of the extr_mode. */
772 1641 : scalar_int_mode imode;
773 1641 : machine_mode vmode;
774 3282 : if (!int_mode_for_size (GET_MODE_BITSIZE (extr_mode), 0).exists (&imode)
775 3282 : || !related_vector_mode (mode, imode, m).exists (&vmode)
776 1641 : || (convert_optab_handler (vec_extract_optab, vmode, imode)
777 : == CODE_FOR_nothing))
778 0 : return false;
779 : /* We assume we can pun mode to vmode and imode to extr_mode. */
780 : return true;
781 : }
782 :
783 : /* OP is either neg_optab or abs_optab and FMODE is the floating-point inner
784 : mode of MODE. Check whether we can implement OP for mode MODE by using
785 : xor_optab to flip the sign bit (for neg_optab) or and_optab to clear the
786 : sign bit (for abs_optab). If so, return the integral mode that should be
787 : used to do the operation and set *BITPOS to the index of the sign bit
788 : (counting from the lsb). */
789 :
790 : opt_machine_mode
791 1105 : get_absneg_bit_mode (optab op, machine_mode mode,
792 : scalar_float_mode fmode, int *bitpos)
793 : {
794 : /* The format has to have a simple sign bit. */
795 1105 : auto fmt = REAL_MODE_FORMAT (fmode);
796 1105 : if (fmt == NULL)
797 0 : return {};
798 :
799 1105 : *bitpos = fmt->signbit_rw;
800 1105 : if (*bitpos < 0)
801 0 : return {};
802 :
803 : /* Don't create negative zeros if the format doesn't support them. */
804 1105 : if (op == neg_optab && !fmt->has_signed_zero)
805 0 : return {};
806 :
807 1105 : if (VECTOR_MODE_P (mode))
808 3 : return related_int_vector_mode (mode);
809 :
810 2254 : if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
811 2170 : return int_mode_for_mode (fmode);
812 :
813 17 : return word_mode;
814 : }
815 :
816 : /* Return true if we can implement OP for mode MODE directly, without resorting
817 : to a libfunc. This usually means that OP will be implemented inline.
818 :
819 : Note that this function cannot tell whether the target pattern chooses to
820 : use libfuncs internally. */
821 :
822 : bool
823 5578247 : can_open_code_p (optab op, machine_mode mode)
824 : {
825 5578247 : if (optab_handler (op, mode) != CODE_FOR_nothing)
826 : return true;
827 :
828 1925886 : if (op == umul_highpart_optab)
829 988 : return can_mult_highpart_p (mode, true);
830 :
831 1924898 : if (op == smul_highpart_optab)
832 1496 : return can_mult_highpart_p (mode, false);
833 :
834 1923402 : machine_mode new_mode;
835 1923402 : scalar_float_mode fmode;
836 1923402 : int bitpos;
837 1923402 : if ((op == neg_optab || op == abs_optab)
838 1719 : && is_a<scalar_float_mode> (GET_MODE_INNER (mode), &fmode)
839 1923402 : && get_absneg_bit_mode (op, mode, fmode, &bitpos).exists (&new_mode)
840 1923403 : && can_implement_p (op == neg_optab ? xor_optab : and_optab, new_mode))
841 1 : return true;
842 :
843 : return false;
844 : }
845 :
846 : /* Return true if we can implement OP for mode MODE in some way, either by
847 : open-coding it or by calling a libfunc. */
848 :
849 : bool
850 5578247 : can_implement_p (optab op, machine_mode mode)
851 : {
852 5578247 : return can_open_code_p (op, mode) || optab_libfunc (op, mode);
853 : }
|