Branch data Line data Source code
1 : : /* IR-agnostic target query functions relating to optabs
2 : : Copyright (C) 1987-2025 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 : 82875 : convert_optab_handler (convert_optab optab, machine_mode to_mode,
48 : : machine_mode from_mode, optimization_type opt_type)
49 : : {
50 : 82875 : insn_code icode = convert_optab_handler (optab, to_mode, from_mode);
51 : 82875 : if (icode == CODE_FOR_nothing
52 : 82875 : || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type))
53 : 82281 : 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 : 3997900 : direct_optab_handler (convert_optab optab, machine_mode mode,
63 : : optimization_type opt_type)
64 : : {
65 : 3997900 : insn_code icode = direct_optab_handler (optab, mode);
66 : 3997900 : if (icode == CODE_FOR_nothing
67 : 3997900 : || !targetm.optab_supported_p (optab, mode, mode, opt_type))
68 : 3657699 : 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 : 3588981 : 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 : 3588981 : direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
132 : 3588981 : enum insn_code icode = direct_optab_handler (optab, mode);
133 : 3588981 : if (icode == CODE_FOR_nothing)
134 : : return false;
135 : :
136 : 1567839 : const struct insn_data_d *data = &insn_data[icode];
137 : :
138 : 1567839 : machine_mode pos_mode = data->operand[pos_op].mode;
139 : 1567839 : if (pos_mode == VOIDmode)
140 : 0 : pos_mode = word_mode;
141 : :
142 : 1567839 : insn->icode = icode;
143 : 1567839 : insn->field_mode = as_a <scalar_int_mode> (mode);
144 : 1567839 : if (type == ET_unaligned_mem)
145 : 0 : insn->struct_mode = opt_scalar_int_mode ();
146 : : else
147 : 1567839 : insn->struct_mode = insn->field_mode;
148 : 1567839 : insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
149 : 1567839 : 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 : 3588981 : get_extraction_insn (extraction_insn *insn,
158 : : enum extraction_pattern pattern,
159 : : enum extraction_type type,
160 : : machine_mode mode)
161 : : {
162 : 3588981 : switch (pattern)
163 : : {
164 : 578439 : case EP_insv:
165 : 578439 : if (targetm.have_insv ()
166 : 578439 : && get_traditional_extraction_insn (insn, type, mode,
167 : : targetm.code_for_insv, 0, 3))
168 : : return true;
169 : 578439 : return get_optab_extraction_insn (insn, type, mode, insv_optab,
170 : 578439 : insvmisalign_optab, 2);
171 : :
172 : 745537 : case EP_extv:
173 : 745537 : if (targetm.have_extv ()
174 : 745537 : && get_traditional_extraction_insn (insn, type, mode,
175 : : targetm.code_for_extv, 1, 0))
176 : : return true;
177 : 745537 : return get_optab_extraction_insn (insn, type, mode, extv_optab,
178 : 745537 : extvmisalign_optab, 3);
179 : :
180 : 2265005 : case EP_extzv:
181 : 2265005 : if (targetm.have_extzv ()
182 : 2265005 : && get_traditional_extraction_insn (insn, type, mode,
183 : : targetm.code_for_extzv, 1, 0))
184 : : return true;
185 : 2265005 : return get_optab_extraction_insn (insn, type, mode, extzv_optab,
186 : 2265005 : 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 : 1901690 : 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 : 1901690 : opt_scalar_int_mode mode_iter;
211 : :
212 : 3922832 : FOR_EACH_MODE_FROM (mode_iter, smallest_int_mode_for_size (struct_bits))
213 : : {
214 : 3588981 : scalar_int_mode mode = mode_iter.require ();
215 : 3588981 : if (get_extraction_insn (insn, pattern, type, mode))
216 : : {
217 : 1567839 : FOR_EACH_MODE_FROM (mode_iter, mode)
218 : : {
219 : 1567839 : mode = mode_iter.require ();
220 : 3135678 : if (maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (field_mode))
221 : 1567839 : || TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
222 : : field_mode))
223 : : break;
224 : 0 : get_extraction_insn (insn, pattern, type, mode);
225 : : }
226 : 1567839 : 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 : 1687074 : 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 : 1687074 : return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
249 : 1687074 : 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 : 214616 : 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 : 214616 : unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
268 : 214616 : + bitsize
269 : 214616 : + BITS_PER_UNIT - 1);
270 : 214616 : struct_bits -= struct_bits % BITS_PER_UNIT;
271 : 214616 : return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
272 : 214616 : 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 : 5321308 : can_extend_p (machine_mode to_mode, machine_mode from_mode,
281 : : int unsignedp)
282 : : {
283 : 5321308 : if (unsignedp < 0 && targetm.have_ptr_extend ())
284 : 0 : return targetm.code_for_ptr_extend;
285 : :
286 : 5321308 : convert_optab tab = unsignedp ? zext_optab : sext_optab;
287 : 5321308 : 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 : 375046 : can_float_p (machine_mode fltmode, machine_mode fixmode,
296 : : int unsignedp)
297 : : {
298 : 375046 : convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
299 : 375046 : 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 : 253227 : can_fix_p (machine_mode fixmode, machine_mode fltmode,
311 : : int unsignedp, bool *truncp_ptr)
312 : : {
313 : 253227 : convert_optab tab;
314 : 253227 : enum insn_code icode;
315 : :
316 : 253227 : tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
317 : 253227 : icode = convert_optab_handler (tab, fixmode, fltmode);
318 : 253227 : if (icode != CODE_FOR_nothing)
319 : : {
320 : 51087 : *truncp_ptr = false;
321 : 51087 : 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 : 202140 : tab = unsignedp ? ufix_optab : sfix_optab;
328 : 202140 : icode = convert_optab_handler (tab, fixmode, fltmode);
329 : 202140 : if (icode != CODE_FOR_nothing
330 : 202140 : && 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 : 1318019 : can_conditionally_move_p (machine_mode mode)
349 : : {
350 : 1318019 : 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 : 765985 : qimode_for_vec_perm (machine_mode mode)
360 : : {
361 : 765985 : if (GET_MODE_INNER (mode) != QImode
362 : 1491676 : && multiple_p (GET_MODE_PRECISION (GET_MODE_INNER (mode)),
363 : 725691 : GET_MODE_PRECISION (QImode)))
364 : 1451382 : return related_vector_mode (mode, QImode, GET_MODE_SIZE (mode));
365 : 40294 : 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 : 1485911 : selector_fits_mode_p (machine_mode mode, const vec_perm_indices &sel)
373 : : {
374 : 1485911 : unsigned HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE_INNER (mode));
375 : 1485911 : return (mask == HOST_WIDE_INT_M1U
376 : 1485911 : || 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 : 865 : 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 : 865 : if (!VECTOR_MODE_P (mode))
389 : : return false;
390 : :
391 : 614 : 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 : 603 : machine_mode qimode;
396 : 603 : if (!qimode_for_vec_perm (mode).exists (&qimode)
397 : 974 : || maybe_gt (GET_MODE_NUNITS (qimode), GET_MODE_MASK (QImode) + 1))
398 : 116 : return false;
399 : :
400 : 487 : 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 : 872019 : 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 : 872019 : if (!VECTOR_MODE_P (mode))
432 : : return false;
433 : :
434 : : /* It's probably cheaper to test for the variable case first. */
435 : 869991 : if (op_mode == mode && allow_variable_p && selector_fits_mode_p (mode, sel))
436 : : {
437 : 826113 : if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
438 : 872019 : 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 : 693043 : machine_mode qimode;
444 : 693043 : if (qimode_for_vec_perm (mode).exists (&qimode))
445 : : {
446 : 659798 : vec_perm_indices qimode_indices;
447 : 1319596 : qimode_indices.new_expanded_vector (sel, GET_MODE_UNIT_SIZE (mode));
448 : 659798 : if (selector_fits_mode_p (qimode, qimode_indices)
449 : 659798 : && (direct_optab_handler (vec_perm_optab, qimode)
450 : : != CODE_FOR_nothing))
451 : 6 : return true;
452 : 659798 : }
453 : : }
454 : :
455 : 736915 : if (targetm.vectorize.vec_perm_const != NULL)
456 : : {
457 : 736915 : 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 : 307122 : find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
477 : : machine_mode from_mode,
478 : : machine_mode *found_mode)
479 : : {
480 : 307122 : machine_mode limit_mode = to_mode;
481 : 307122 : if (is_a <scalar_int_mode> (from_mode))
482 : : {
483 : 306467 : 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 : 306467 : if (GET_MODE_CLASS (limit_mode) == MODE_PARTIAL_INT)
491 : 0 : limit_mode = GET_MODE_WIDER_MODE (limit_mode).require ();
492 : : }
493 : 655 : 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 : 655 : gcc_checking_assert (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
501 : : && from_mode < to_mode);
502 : 576457 : FOR_EACH_MODE (from_mode, from_mode, limit_mode)
503 : : {
504 : 330601 : enum insn_code handler = convert_optab_handler (op, to_mode, from_mode);
505 : :
506 : 330601 : if (handler != CODE_FOR_nothing)
507 : : {
508 : 61266 : if (found_mode)
509 : 10285 : *found_mode = from_mode;
510 : 61266 : 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 : 87182 : can_mult_highpart_p (machine_mode mode, bool uns_p)
523 : : {
524 : 87182 : optab op;
525 : 87182 : scalar_int_mode int_mode, wider_mode;
526 : :
527 : 87182 : op = uns_p ? umul_highpart_optab : smul_highpart_optab;
528 : 87182 : 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 : 83312 : if (is_a <scalar_int_mode> (mode, &int_mode)
533 : 4493 : && GET_MODE_WIDER_MODE (int_mode).exists (&wider_mode))
534 : : {
535 : 4493 : op = uns_p ? umul_widen_optab : smul_widen_optab;
536 : 4493 : 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 : 4493 : if (optab_handler (smul_optab, wider_mode) != CODE_FOR_nothing
541 : 4493 : && 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 : 83312 : if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
547 : : return 0;
548 : :
549 : 157638 : poly_int64 nunits = GET_MODE_NUNITS (mode);
550 : :
551 : 78819 : op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
552 : 78819 : if (optab_handler (op, mode) != CODE_FOR_nothing)
553 : : {
554 : 23021 : op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
555 : 23021 : if (optab_handler (op, mode) != CODE_FOR_nothing)
556 : : {
557 : : /* The encoding has 2 interleaved stepped patterns. */
558 : 23021 : vec_perm_builder sel (nunits, 2, 3);
559 : 161147 : for (unsigned int i = 0; i < 6; ++i)
560 : 276252 : sel.quick_push (!BYTES_BIG_ENDIAN
561 : 138126 : + (i & ~1)
562 : 207189 : + ((i & 1) ? nunits : 0));
563 : 23021 : vec_perm_indices indices (sel, 2, nunits);
564 : 23021 : if (can_vec_perm_const_p (mode, mode, indices))
565 : 23021 : return 3;
566 : 23021 : }
567 : : }
568 : :
569 : 55798 : op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
570 : 55798 : if (optab_handler (op, mode) != CODE_FOR_nothing)
571 : : {
572 : 306 : op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
573 : 306 : if (optab_handler (op, mode) != CODE_FOR_nothing)
574 : : {
575 : : /* The encoding has a single stepped pattern. */
576 : 306 : vec_perm_builder sel (nunits, 1, 3);
577 : 1224 : for (unsigned int i = 0; i < 3; ++i)
578 : 918 : sel.quick_push (2 * i + (BYTES_BIG_ENDIAN ? 0 : 1));
579 : 306 : vec_perm_indices indices (sel, 2, nunits);
580 : 306 : if (can_vec_perm_const_p (mode, mode, indices))
581 : 306 : return 4;
582 : 306 : }
583 : : }
584 : :
585 : : return 0;
586 : : }
587 : :
588 : : /* Return true if there is a compare_and_swap pattern. */
589 : :
590 : : bool
591 : 125713 : can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
592 : : {
593 : 125713 : enum insn_code icode;
594 : :
595 : : /* Check for __atomic_compare_and_swap. */
596 : 125713 : icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
597 : 125713 : if (icode != CODE_FOR_nothing)
598 : : return true;
599 : :
600 : : /* Check for __sync_compare_and_swap. */
601 : 132 : icode = optab_handler (sync_compare_and_swap_optab, mode);
602 : 132 : if (icode != CODE_FOR_nothing)
603 : : return true;
604 : 132 : 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 : 181955 : can_atomic_load_p (machine_mode mode)
635 : : {
636 : 181955 : enum insn_code icode;
637 : :
638 : : /* Does the target supports the load directly? */
639 : 181955 : icode = direct_optab_handler (atomic_load_optab, mode);
640 : 181955 : 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 : 4046 : 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 : 1128248 : 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 : 1128248 : static bool init[2] = { false, false };
657 : 1128248 : 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 : 1128248 : if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
662 : : return false;
663 : :
664 : 1128248 : if (!init[speed_p])
665 : : {
666 : 40770 : rtx reg = gen_raw_REG (word_mode, 10000);
667 : 40770 : int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
668 : : word_mode, speed_p);
669 : 40770 : cheap[speed_p] = cost < COSTS_N_INSNS (3);
670 : 40770 : init[speed_p] = true;
671 : : }
672 : :
673 : 1128248 : 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 : 145932 : supported_vec_convert_optab (optab op, machine_mode mode)
682 : : {
683 : 145932 : int start = mode == VOIDmode ? 0 : mode;
684 : 145932 : int end = mode == VOIDmode ? MAX_MACHINE_MODE - 1 : mode;
685 : 145932 : enum insn_code icode = CODE_FOR_nothing;
686 : 291864 : for (int i = start; i <= end; ++i)
687 : 145932 : if (VECTOR_MODE_P ((machine_mode) i))
688 : 4523892 : for (int j = MIN_MODE_VECTOR_INT; j < MAX_MODE_VECTOR_INT; ++j)
689 : : {
690 : 8755920 : if ((icode
691 : 4377960 : = 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 : 115860 : supports_vec_gather_load_p (machine_mode mode, vec<int> *elsvals)
707 : : {
708 : 115860 : enum insn_code icode = CODE_FOR_nothing;
709 : 115860 : 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 : 41483 : icode = supported_vec_convert_optab (mask_gather_load_optab, mode);
716 : 41483 : if (icode == CODE_FOR_nothing)
717 : 41483 : icode = supported_vec_convert_optab (mask_len_gather_load_optab, mode);
718 : 41483 : if (icode == CODE_FOR_nothing)
719 : 41483 : icode = supported_vec_convert_optab (gather_load_optab, mode);
720 : 82966 : this_fn_optabs->supports_vec_gather_load[mode]
721 : 82966 : = (icode != CODE_FOR_nothing) ? 1 : -1;
722 : : }
723 : :
724 : 115860 : 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 : 115860 : 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 : 62311 : supports_vec_scatter_store_p (machine_mode mode)
737 : : {
738 : 62311 : enum insn_code icode;
739 : 62311 : if (!this_fn_optabs->supports_vec_scatter_store[mode])
740 : : {
741 : 7161 : icode = supported_vec_convert_optab (scatter_store_optab, mode);
742 : 7161 : if (icode == CODE_FOR_nothing)
743 : 7161 : icode = supported_vec_convert_optab (mask_scatter_store_optab, mode);
744 : 7161 : if (icode == CODE_FOR_nothing)
745 : 7161 : icode = supported_vec_convert_optab (mask_len_scatter_store_optab,
746 : : mode);
747 : 14322 : this_fn_optabs->supports_vec_scatter_store[mode]
748 : 7161 : = (icode != CODE_FOR_nothing) ? 1 : -1;
749 : : }
750 : :
751 : 62311 : 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 : 4276 : can_vec_extract (machine_mode mode, machine_mode extr_mode)
759 : : {
760 : 4276 : unsigned m;
761 : 2478 : if (!VECTOR_MODE_P (mode)
762 : 8552 : || !constant_multiple_p (GET_MODE_SIZE (mode),
763 : 4274 : GET_MODE_SIZE (extr_mode), &m))
764 : : return false;
765 : :
766 : 4274 : 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 : 1627 : scalar_int_mode imode;
773 : 1627 : machine_mode vmode;
774 : 3254 : if (!int_mode_for_size (GET_MODE_BITSIZE (extr_mode), 0).exists (&imode)
775 : 3254 : || !related_vector_mode (mode, imode, m).exists (&vmode)
776 : 1627 : || (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 : 54 : 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 : 54 : auto fmt = REAL_MODE_FORMAT (fmode);
796 : 54 : if (fmt == NULL)
797 : 0 : return {};
798 : :
799 : 54 : *bitpos = fmt->signbit_rw;
800 : 54 : if (*bitpos < 0)
801 : 0 : return {};
802 : :
803 : : /* Don't create negative zeros if the format doesn't support them. */
804 : 54 : if (op == neg_optab && !fmt->has_signed_zero)
805 : 0 : return {};
806 : :
807 : 54 : if (VECTOR_MODE_P (mode))
808 : 3 : return related_int_vector_mode (mode);
809 : :
810 : 102 : if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
811 : 68 : 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 : 5315870 : can_open_code_p (optab op, machine_mode mode)
824 : : {
825 : 5315870 : if (optab_handler (op, mode) != CODE_FOR_nothing)
826 : : return true;
827 : :
828 : 1820601 : if (op == umul_highpart_optab)
829 : 982 : return can_mult_highpart_p (mode, true);
830 : :
831 : 1819619 : if (op == smul_highpart_optab)
832 : 1493 : return can_mult_highpart_p (mode, false);
833 : :
834 : 1818126 : machine_mode new_mode;
835 : 1818126 : scalar_float_mode fmode;
836 : 1818126 : int bitpos;
837 : 1818126 : if ((op == neg_optab || op == abs_optab)
838 : 866 : && is_a<scalar_float_mode> (GET_MODE_INNER (mode), &fmode)
839 : 1818126 : && get_absneg_bit_mode (op, mode, fmode, &bitpos).exists (&new_mode)
840 : 1818127 : && 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 : 5315870 : can_implement_p (optab op, machine_mode mode)
851 : : {
852 : 5315870 : return can_open_code_p (op, mode) || optab_libfunc (op, mode);
853 : : }
|