Branch data Line data Source code
1 : : /* IR-agnostic target query functions relating to optabs
2 : : Copyright (C) 1987-2024 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 : :
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
38 : :
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. */
42 : :
43 : : insn_code
44 : 4839 : convert_optab_handler (convert_optab optab, machine_mode to_mode,
45 : : machine_mode from_mode, optimization_type opt_type)
46 : : {
47 : 4839 : insn_code icode = convert_optab_handler (optab, to_mode, from_mode);
48 : 4839 : if (icode == CODE_FOR_nothing
49 : 4839 : || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type))
50 : 4385 : return CODE_FOR_nothing;
51 : : return icode;
52 : : }
53 : :
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. */
57 : :
58 : : insn_code
59 : 4768163 : direct_optab_handler (convert_optab optab, machine_mode mode,
60 : : optimization_type opt_type)
61 : : {
62 : 4768163 : insn_code icode = direct_optab_handler (optab, mode);
63 : 4768163 : if (icode == CODE_FOR_nothing
64 : 4768163 : || !targetm.optab_supported_p (optab, mode, mode, opt_type))
65 : 4563718 : return CODE_FOR_nothing;
66 : : return icode;
67 : : }
68 : :
69 : : /* Enumerates the possible types of structure operand to an
70 : : extraction_insn. */
71 : : enum extraction_type { ET_unaligned_mem, ET_reg };
72 : :
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). */
79 : :
80 : : static bool
81 : 0 : 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)
86 : : {
87 : 0 : const struct insn_data_d *data = &insn_data[icode];
88 : :
89 : 0 : machine_mode struct_mode = data->operand[struct_op].mode;
90 : 0 : if (struct_mode == VOIDmode)
91 : 0 : struct_mode = word_mode;
92 : 0 : if (mode != struct_mode)
93 : : return false;
94 : :
95 : 0 : machine_mode field_mode = data->operand[field_op].mode;
96 : 0 : if (field_mode == VOIDmode)
97 : 0 : field_mode = word_mode;
98 : :
99 : 0 : machine_mode pos_mode = data->operand[struct_op + 2].mode;
100 : 0 : if (pos_mode == VOIDmode)
101 : 0 : pos_mode = word_mode;
102 : :
103 : 0 : insn->icode = icode;
104 : 0 : insn->field_mode = as_a <scalar_int_mode> (field_mode);
105 : 0 : if (type == ET_unaligned_mem)
106 : 0 : insn->struct_mode = byte_mode;
107 : 0 : else if (struct_mode == BLKmode)
108 : 0 : insn->struct_mode = opt_scalar_int_mode ();
109 : : else
110 : 0 : insn->struct_mode = as_a <scalar_int_mode> (struct_mode);
111 : 0 : insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
112 : 0 : return true;
113 : : }
114 : :
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.
117 : :
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. */
121 : :
122 : : static bool
123 : 3208069 : 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)
127 : : {
128 : 3208069 : direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
129 : 3208069 : enum insn_code icode = direct_optab_handler (optab, mode);
130 : 3208069 : if (icode == CODE_FOR_nothing)
131 : : return false;
132 : :
133 : 1385798 : const struct insn_data_d *data = &insn_data[icode];
134 : :
135 : 1385798 : machine_mode pos_mode = data->operand[pos_op].mode;
136 : 1385798 : if (pos_mode == VOIDmode)
137 : 0 : pos_mode = word_mode;
138 : :
139 : 1385798 : insn->icode = icode;
140 : 1385798 : insn->field_mode = as_a <scalar_int_mode> (mode);
141 : 1385798 : if (type == ET_unaligned_mem)
142 : 0 : insn->struct_mode = opt_scalar_int_mode ();
143 : : else
144 : 1385798 : insn->struct_mode = insn->field_mode;
145 : 1385798 : insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
146 : 1385798 : return true;
147 : : }
148 : :
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. */
152 : :
153 : : static bool
154 : 3208069 : get_extraction_insn (extraction_insn *insn,
155 : : enum extraction_pattern pattern,
156 : : enum extraction_type type,
157 : : machine_mode mode)
158 : : {
159 : 3208069 : switch (pattern)
160 : : {
161 : 521093 : case EP_insv:
162 : 521093 : if (targetm.have_insv ()
163 : 521093 : && get_traditional_extraction_insn (insn, type, mode,
164 : : targetm.code_for_insv, 0, 3))
165 : : return true;
166 : 521093 : return get_optab_extraction_insn (insn, type, mode, insv_optab,
167 : 521093 : insvmisalign_optab, 2);
168 : :
169 : 714012 : case EP_extv:
170 : 714012 : if (targetm.have_extv ()
171 : 714012 : && get_traditional_extraction_insn (insn, type, mode,
172 : : targetm.code_for_extv, 1, 0))
173 : : return true;
174 : 714012 : return get_optab_extraction_insn (insn, type, mode, extv_optab,
175 : 714012 : extvmisalign_optab, 3);
176 : :
177 : 1972964 : case EP_extzv:
178 : 1972964 : if (targetm.have_extzv ()
179 : 1972964 : && get_traditional_extraction_insn (insn, type, mode,
180 : : targetm.code_for_extzv, 1, 0))
181 : : return true;
182 : 1972964 : return get_optab_extraction_insn (insn, type, mode, extzv_optab,
183 : 1972964 : extzvmisalign_optab, 3);
184 : :
185 : 0 : default:
186 : 0 : gcc_unreachable ();
187 : : }
188 : : }
189 : :
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.
194 : :
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. */
199 : :
200 : : static bool
201 : 1700428 : 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)
206 : : {
207 : 1700428 : opt_scalar_int_mode mode_iter;
208 : 3522699 : FOR_EACH_MODE_FROM (mode_iter, smallest_int_mode_for_size (struct_bits))
209 : : {
210 : 3208069 : scalar_int_mode mode = mode_iter.require ();
211 : 3208069 : if (get_extraction_insn (insn, pattern, type, mode))
212 : : {
213 : 1385798 : FOR_EACH_MODE_FROM (mode_iter, mode)
214 : : {
215 : 1385798 : mode = mode_iter.require ();
216 : 2771596 : if (maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (field_mode))
217 : 1385798 : || TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
218 : : field_mode))
219 : : break;
220 : 0 : get_extraction_insn (insn, pattern, type, mode);
221 : : }
222 : 1385798 : return true;
223 : : }
224 : : }
225 : : return false;
226 : : }
227 : :
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.
232 : :
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
236 : : in both cases. */
237 : :
238 : : bool
239 : 1499231 : 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)
243 : : {
244 : 1499231 : return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
245 : 1499231 : field_mode);
246 : : }
247 : :
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.
253 : :
254 : : The instructions considered here only access bytes that overlap
255 : : the bitfield; they do not touch any surrounding bytes. */
256 : :
257 : : bool
258 : 201197 : 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)
262 : : {
263 : 201197 : unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
264 : 201197 : + bitsize
265 : 201197 : + BITS_PER_UNIT - 1);
266 : 201197 : struct_bits -= struct_bits % BITS_PER_UNIT;
267 : 201197 : return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
268 : 201197 : struct_bits, field_mode);
269 : : }
270 : :
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. */
274 : :
275 : : enum insn_code
276 : 5171136 : can_extend_p (machine_mode to_mode, machine_mode from_mode,
277 : : int unsignedp)
278 : : {
279 : 5171136 : if (unsignedp < 0 && targetm.have_ptr_extend ())
280 : 0 : return targetm.code_for_ptr_extend;
281 : :
282 : 5171136 : convert_optab tab = unsignedp ? zext_optab : sext_optab;
283 : 5171136 : return convert_optab_handler (tab, to_mode, from_mode);
284 : : }
285 : :
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. */
289 : :
290 : : enum insn_code
291 : 359835 : can_float_p (machine_mode fltmode, machine_mode fixmode,
292 : : int unsignedp)
293 : : {
294 : 359835 : convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
295 : 359835 : return convert_optab_handler (tab, fltmode, fixmode);
296 : : }
297 : :
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.
301 : :
302 : : On a successful return, set *TRUNCP_PTR to true if it is necessary to
303 : : output an explicit FTRUNC before the instruction. */
304 : :
305 : : enum insn_code
306 : 253088 : can_fix_p (machine_mode fixmode, machine_mode fltmode,
307 : : int unsignedp, bool *truncp_ptr)
308 : : {
309 : 253088 : convert_optab tab;
310 : 253088 : enum insn_code icode;
311 : :
312 : 253088 : tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
313 : 253088 : icode = convert_optab_handler (tab, fixmode, fltmode);
314 : 253088 : if (icode != CODE_FOR_nothing)
315 : : {
316 : 49175 : *truncp_ptr = false;
317 : 49175 : return icode;
318 : : }
319 : :
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 : 203913 : tab = unsignedp ? ufix_optab : sfix_optab;
324 : 203913 : icode = convert_optab_handler (tab, fixmode, fltmode);
325 : 203913 : if (icode != CODE_FOR_nothing
326 : 203913 : && optab_handler (ftrunc_optab, fltmode) != CODE_FOR_nothing)
327 : : {
328 : 0 : *truncp_ptr = true;
329 : 0 : return icode;
330 : : }
331 : :
332 : : return CODE_FOR_nothing;
333 : : }
334 : :
335 : : /* Return nonzero if a conditional move of mode MODE is supported.
336 : :
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? */
342 : :
343 : : bool
344 : 670407 : can_conditionally_move_p (machine_mode mode)
345 : : {
346 : 670407 : return direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing;
347 : : }
348 : :
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
352 : : byte vector mode. */
353 : :
354 : : opt_machine_mode
355 : 636987 : qimode_for_vec_perm (machine_mode mode)
356 : : {
357 : 1273974 : if (GET_MODE_INNER (mode) != QImode)
358 : 1209674 : return related_vector_mode (mode, QImode, GET_MODE_SIZE (mode));
359 : 32150 : return opt_machine_mode ();
360 : : }
361 : :
362 : : /* Return true if selector SEL can be represented in the integer
363 : : equivalent of vector mode MODE. */
364 : :
365 : : bool
366 : 1244822 : selector_fits_mode_p (machine_mode mode, const vec_perm_indices &sel)
367 : : {
368 : 1244822 : unsigned HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE_INNER (mode));
369 : 1244822 : return (mask == HOST_WIDE_INT_M1U
370 : 1244822 : || sel.all_in_range_p (0, mask + 1));
371 : : }
372 : :
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. */
376 : :
377 : : bool
378 : 863 : can_vec_perm_var_p (machine_mode mode)
379 : : {
380 : : /* If the target doesn't implement a vector mode for the vector type,
381 : : then no operations are supported. */
382 : 863 : if (!VECTOR_MODE_P (mode))
383 : : return false;
384 : :
385 : 612 : if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
386 : : return true;
387 : :
388 : : /* We allow fallback to a QI vector mode, and adjust the mask. */
389 : 601 : machine_mode qimode;
390 : 601 : if (!qimode_for_vec_perm (mode).exists (&qimode)
391 : 1086 : || maybe_gt (GET_MODE_NUNITS (qimode), GET_MODE_MASK (QImode) + 1))
392 : 116 : return false;
393 : :
394 : 485 : if (direct_optab_handler (vec_perm_optab, qimode) == CODE_FOR_nothing)
395 : : return false;
396 : :
397 : : /* In order to support the lowering of variable permutations,
398 : : we need to support shifts and adds. */
399 : 0 : if (GET_MODE_UNIT_SIZE (mode) > 2
400 : 0 : && optab_handler (ashl_optab, mode) == CODE_FOR_nothing
401 : 0 : && optab_handler (vashl_optab, mode) == CODE_FOR_nothing)
402 : : return false;
403 : 0 : if (optab_handler (add_optab, qimode) == CODE_FOR_nothing)
404 : : return false;
405 : :
406 : : return true;
407 : : }
408 : :
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).
413 : :
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
417 : : with here. */
418 : :
419 : : bool
420 : 708945 : can_vec_perm_const_p (machine_mode mode, machine_mode op_mode,
421 : : const vec_perm_indices &sel, bool allow_variable_p)
422 : : {
423 : : /* If the target doesn't implement a vector mode for the vector type,
424 : : then no operations are supported. */
425 : 708945 : if (!VECTOR_MODE_P (mode))
426 : : return false;
427 : :
428 : : /* It's probably cheaper to test for the variable case first. */
429 : 706925 : if (op_mode == mode && allow_variable_p && selector_fits_mode_p (mode, sel))
430 : : {
431 : 691677 : if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
432 : 708945 : return true;
433 : :
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
436 : : compile time. */
437 : 578021 : machine_mode qimode;
438 : 578021 : if (qimode_for_vec_perm (mode).exists (&qimode))
439 : : {
440 : 553145 : vec_perm_indices qimode_indices;
441 : 1106290 : qimode_indices.new_expanded_vector (sel, GET_MODE_UNIT_SIZE (mode));
442 : 553145 : if (selector_fits_mode_p (qimode, qimode_indices)
443 : 553145 : && (direct_optab_handler (vec_perm_optab, qimode)
444 : : != CODE_FOR_nothing))
445 : 14 : return true;
446 : 553145 : }
447 : : }
448 : :
449 : 593255 : if (targetm.vectorize.vec_perm_const != NULL)
450 : : {
451 : 593255 : if (targetm.vectorize.vec_perm_const (mode, op_mode, NULL_RTX, NULL_RTX,
452 : : NULL_RTX, sel))
453 : : return true;
454 : :
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. */
460 : : }
461 : :
462 : : return false;
463 : : }
464 : :
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. */
468 : :
469 : : enum insn_code
470 : 267631 : find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
471 : : machine_mode from_mode,
472 : : machine_mode *found_mode)
473 : : {
474 : 267631 : machine_mode limit_mode = to_mode;
475 : 267631 : if (is_a <scalar_int_mode> (from_mode))
476 : : {
477 : 267362 : 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
483 : : MODE_INT. */
484 : 267362 : if (GET_MODE_CLASS (limit_mode) == MODE_PARTIAL_INT)
485 : 0 : limit_mode = GET_MODE_WIDER_MODE (limit_mode).require ();
486 : : }
487 : : else
488 : 269 : gcc_checking_assert (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
489 : : && from_mode < to_mode);
490 : 496271 : FOR_EACH_MODE (from_mode, from_mode, limit_mode)
491 : : {
492 : 285898 : enum insn_code handler = convert_optab_handler (op, to_mode, from_mode);
493 : :
494 : 285898 : if (handler != CODE_FOR_nothing)
495 : : {
496 : 57258 : if (found_mode)
497 : 10178 : *found_mode = from_mode;
498 : 57258 : return handler;
499 : : }
500 : : }
501 : :
502 : : return CODE_FOR_nothing;
503 : : }
504 : :
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. */
508 : :
509 : : int
510 : 79273 : can_mult_highpart_p (machine_mode mode, bool uns_p)
511 : : {
512 : 79273 : optab op;
513 : :
514 : 79273 : op = uns_p ? umul_highpart_optab : smul_highpart_optab;
515 : 79273 : if (optab_handler (op, mode) != CODE_FOR_nothing)
516 : : return 1;
517 : :
518 : : /* If the mode is an integral vector, synth from widening operations. */
519 : 74278 : if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
520 : : return 0;
521 : :
522 : 138828 : poly_int64 nunits = GET_MODE_NUNITS (mode);
523 : :
524 : 69414 : op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
525 : 69414 : if (optab_handler (op, mode) != CODE_FOR_nothing)
526 : : {
527 : 19515 : op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
528 : 19515 : if (optab_handler (op, mode) != CODE_FOR_nothing)
529 : : {
530 : : /* The encoding has 2 interleaved stepped patterns. */
531 : 19515 : vec_perm_builder sel (nunits, 2, 3);
532 : 136605 : for (unsigned int i = 0; i < 6; ++i)
533 : 234180 : sel.quick_push (!BYTES_BIG_ENDIAN
534 : 117090 : + (i & ~1)
535 : 117090 : + ((i & 1) ? nunits : 0));
536 : 19515 : vec_perm_indices indices (sel, 2, nunits);
537 : 19515 : if (can_vec_perm_const_p (mode, mode, indices))
538 : 19515 : return 2;
539 : 19515 : }
540 : : }
541 : :
542 : 49899 : op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
543 : 49899 : if (optab_handler (op, mode) != CODE_FOR_nothing)
544 : : {
545 : 352 : op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
546 : 352 : if (optab_handler (op, mode) != CODE_FOR_nothing)
547 : : {
548 : : /* The encoding has a single stepped pattern. */
549 : 352 : vec_perm_builder sel (nunits, 1, 3);
550 : 1408 : for (unsigned int i = 0; i < 3; ++i)
551 : 1056 : sel.quick_push (2 * i + (BYTES_BIG_ENDIAN ? 0 : 1));
552 : 352 : vec_perm_indices indices (sel, 2, nunits);
553 : 352 : if (can_vec_perm_const_p (mode, mode, indices))
554 : 352 : return 3;
555 : 352 : }
556 : : }
557 : :
558 : : return 0;
559 : : }
560 : :
561 : : /* Return true if there is a compare_and_swap pattern. */
562 : :
563 : : bool
564 : 97672 : can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
565 : : {
566 : 97672 : enum insn_code icode;
567 : :
568 : : /* Check for __atomic_compare_and_swap. */
569 : 97672 : icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
570 : 97672 : if (icode != CODE_FOR_nothing)
571 : : return true;
572 : :
573 : : /* Check for __sync_compare_and_swap. */
574 : 130 : icode = optab_handler (sync_compare_and_swap_optab, mode);
575 : 130 : if (icode != CODE_FOR_nothing)
576 : : return true;
577 : 130 : if (allow_libcall && optab_libfunc (sync_compare_and_swap_optab, mode))
578 : : return true;
579 : :
580 : : /* No inline compare and swap. */
581 : : return false;
582 : : }
583 : :
584 : : /* Return true if an atomic exchange can be performed. */
585 : :
586 : : bool
587 : 88 : can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
588 : : {
589 : 88 : enum insn_code icode;
590 : :
591 : : /* Check for __atomic_exchange. */
592 : 88 : icode = direct_optab_handler (atomic_exchange_optab, mode);
593 : 88 : if (icode != CODE_FOR_nothing)
594 : : return true;
595 : :
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. */
599 : :
600 : 0 : return can_compare_and_swap_p (mode, allow_libcall);
601 : : }
602 : :
603 : : /* Return true if an atomic load can be performed without falling back to
604 : : a compare-and-swap. */
605 : :
606 : : bool
607 : 152665 : can_atomic_load_p (machine_mode mode)
608 : : {
609 : 152665 : enum insn_code icode;
610 : :
611 : : /* Does the target supports the load directly? */
612 : 152665 : icode = direct_optab_handler (atomic_load_optab, mode);
613 : 152665 : if (icode != CODE_FOR_nothing)
614 : : return true;
615 : :
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 : 4040 : return known_le (GET_MODE_PRECISION (mode), BITS_PER_WORD);
620 : : }
621 : :
622 : : /* Determine whether "1 << x" is relatively cheap in word_mode. */
623 : :
624 : : bool
625 : 999936 : lshift_cheap_p (bool speed_p)
626 : : {
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 : 999936 : static bool init[2] = { false, false };
630 : 999936 : static bool cheap[2] = { true, true };
631 : :
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 : 999936 : if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
635 : : return false;
636 : :
637 : 999936 : if (!init[speed_p])
638 : : {
639 : 38013 : rtx reg = gen_raw_REG (word_mode, 10000);
640 : 38013 : int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
641 : : word_mode, speed_p);
642 : 38013 : cheap[speed_p] = cost < COSTS_N_INSNS (3);
643 : 38013 : init[speed_p] = true;
644 : : }
645 : :
646 : 999936 : return cheap[speed_p];
647 : : }
648 : :
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. */
652 : :
653 : : static bool
654 : 43854 : supports_vec_convert_optab_p (optab op, machine_mode mode)
655 : : {
656 : 43854 : int start = mode == VOIDmode ? 0 : mode;
657 : 43854 : int end = mode == VOIDmode ? MAX_MACHINE_MODE - 1 : mode;
658 : 87708 : for (int i = start; i <= end; ++i)
659 : 43854 : if (VECTOR_MODE_P ((machine_mode) i))
660 : 1403040 : for (int j = MIN_MODE_VECTOR_INT; j < MAX_MODE_VECTOR_INT; ++j)
661 : 1359195 : if (convert_optab_handler (op, (machine_mode) i,
662 : : (machine_mode) j) != CODE_FOR_nothing)
663 : : return true;
664 : :
665 : : return false;
666 : : }
667 : :
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. */
671 : :
672 : : bool
673 : 72669 : supports_vec_gather_load_p (machine_mode mode)
674 : : {
675 : 72669 : if (!this_fn_optabs->supports_vec_gather_load[mode])
676 : 16860 : this_fn_optabs->supports_vec_gather_load[mode]
677 : 16860 : = (supports_vec_convert_optab_p (gather_load_optab, mode)
678 : 8430 : || supports_vec_convert_optab_p (mask_gather_load_optab, mode)
679 : 8430 : || supports_vec_convert_optab_p (mask_len_gather_load_optab, mode)
680 : : ? 1 : -1);
681 : :
682 : 72669 : return this_fn_optabs->supports_vec_gather_load[mode] > 0;
683 : : }
684 : :
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. */
688 : :
689 : : bool
690 : 48345 : supports_vec_scatter_store_p (machine_mode mode)
691 : : {
692 : 48345 : if (!this_fn_optabs->supports_vec_scatter_store[mode])
693 : 12376 : this_fn_optabs->supports_vec_scatter_store[mode]
694 : 12376 : = (supports_vec_convert_optab_p (scatter_store_optab, mode)
695 : 6188 : || supports_vec_convert_optab_p (mask_scatter_store_optab, mode)
696 : 6188 : || supports_vec_convert_optab_p (mask_len_scatter_store_optab, mode)
697 : : ? 1 : -1);
698 : :
699 : 48345 : return this_fn_optabs->supports_vec_scatter_store[mode] > 0;
700 : : }
701 : :
702 : : /* Whether we can extract part of the vector mode MODE as
703 : : (scalar or vector) mode EXTR_MODE. */
704 : :
705 : : bool
706 : 4028 : can_vec_extract (machine_mode mode, machine_mode extr_mode)
707 : : {
708 : 4028 : unsigned m;
709 : 2387 : if (!VECTOR_MODE_P (mode)
710 : 8056 : || !constant_multiple_p (GET_MODE_SIZE (mode),
711 : 4028 : GET_MODE_SIZE (extr_mode), &m))
712 : 0 : return false;
713 : :
714 : 4028 : if (convert_optab_handler (vec_extract_optab, mode, extr_mode)
715 : : != CODE_FOR_nothing)
716 : : return true;
717 : :
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 : 1353 : scalar_int_mode imode;
721 : 1353 : machine_mode vmode;
722 : 2706 : if (!int_mode_for_size (GET_MODE_BITSIZE (extr_mode), 0).exists (&imode)
723 : 2706 : || !related_vector_mode (mode, imode, m).exists (&vmode)
724 : 2706 : || (convert_optab_handler (vec_extract_optab, vmode, imode)
725 : : == CODE_FOR_nothing))
726 : 0 : return false;
727 : : /* We assume we can pun mode to vmode and imode to extr_mode. */
728 : : return true;
729 : : }
|