111
|
1 /* IR-agnostic target query functions relating to optabs
|
131
|
2 Copyright (C) 1987-2018 Free Software Foundation, Inc.
|
111
|
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"
|
131
|
31 #include "vec-perm-indices.h"
|
111
|
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 convert_optab_handler (convert_optab optab, machine_mode to_mode,
|
|
45 machine_mode from_mode, optimization_type opt_type)
|
|
46 {
|
|
47 insn_code icode = convert_optab_handler (optab, to_mode, from_mode);
|
|
48 if (icode == CODE_FOR_nothing
|
|
49 || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type))
|
|
50 return CODE_FOR_nothing;
|
|
51 return icode;
|
|
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 direct_optab_handler (convert_optab optab, machine_mode mode,
|
|
60 optimization_type opt_type)
|
|
61 {
|
|
62 insn_code icode = direct_optab_handler (optab, mode);
|
|
63 if (icode == CODE_FOR_nothing
|
|
64 || !targetm.optab_supported_p (optab, mode, mode, opt_type))
|
|
65 return CODE_FOR_nothing;
|
|
66 return icode;
|
|
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 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 const struct insn_data_d *data = &insn_data[icode];
|
|
88
|
|
89 machine_mode struct_mode = data->operand[struct_op].mode;
|
|
90 if (struct_mode == VOIDmode)
|
|
91 struct_mode = word_mode;
|
|
92 if (mode != struct_mode)
|
|
93 return false;
|
|
94
|
|
95 machine_mode field_mode = data->operand[field_op].mode;
|
|
96 if (field_mode == VOIDmode)
|
|
97 field_mode = word_mode;
|
|
98
|
|
99 machine_mode pos_mode = data->operand[struct_op + 2].mode;
|
|
100 if (pos_mode == VOIDmode)
|
|
101 pos_mode = word_mode;
|
|
102
|
|
103 insn->icode = icode;
|
|
104 insn->field_mode = as_a <scalar_int_mode> (field_mode);
|
|
105 if (type == ET_unaligned_mem)
|
|
106 insn->struct_mode = byte_mode;
|
|
107 else if (struct_mode == BLKmode)
|
|
108 insn->struct_mode = opt_scalar_int_mode ();
|
|
109 else
|
|
110 insn->struct_mode = as_a <scalar_int_mode> (struct_mode);
|
|
111 insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
|
|
112 return true;
|
|
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 get_optab_extraction_insn (struct 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 direct_optab optab = (type == ET_unaligned_mem ? misalign_optab : reg_optab);
|
|
129 enum insn_code icode = direct_optab_handler (optab, mode);
|
|
130 if (icode == CODE_FOR_nothing)
|
|
131 return false;
|
|
132
|
|
133 const struct insn_data_d *data = &insn_data[icode];
|
|
134
|
|
135 machine_mode pos_mode = data->operand[pos_op].mode;
|
|
136 if (pos_mode == VOIDmode)
|
|
137 pos_mode = word_mode;
|
|
138
|
|
139 insn->icode = icode;
|
|
140 insn->field_mode = as_a <scalar_int_mode> (mode);
|
|
141 if (type == ET_unaligned_mem)
|
|
142 insn->struct_mode = opt_scalar_int_mode ();
|
|
143 else
|
|
144 insn->struct_mode = insn->field_mode;
|
|
145 insn->pos_mode = as_a <scalar_int_mode> (pos_mode);
|
|
146 return true;
|
|
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 get_extraction_insn (extraction_insn *insn,
|
|
155 enum extraction_pattern pattern,
|
|
156 enum extraction_type type,
|
|
157 machine_mode mode)
|
|
158 {
|
|
159 switch (pattern)
|
|
160 {
|
|
161 case EP_insv:
|
|
162 if (targetm.have_insv ()
|
|
163 && get_traditional_extraction_insn (insn, type, mode,
|
|
164 targetm.code_for_insv, 0, 3))
|
|
165 return true;
|
|
166 return get_optab_extraction_insn (insn, type, mode, insv_optab,
|
|
167 insvmisalign_optab, 2);
|
|
168
|
|
169 case EP_extv:
|
|
170 if (targetm.have_extv ()
|
|
171 && get_traditional_extraction_insn (insn, type, mode,
|
|
172 targetm.code_for_extv, 1, 0))
|
|
173 return true;
|
|
174 return get_optab_extraction_insn (insn, type, mode, extv_optab,
|
|
175 extvmisalign_optab, 3);
|
|
176
|
|
177 case EP_extzv:
|
|
178 if (targetm.have_extzv ()
|
|
179 && get_traditional_extraction_insn (insn, type, mode,
|
|
180 targetm.code_for_extzv, 1, 0))
|
|
181 return true;
|
|
182 return get_optab_extraction_insn (insn, type, mode, extzv_optab,
|
|
183 extzvmisalign_optab, 3);
|
|
184
|
|
185 default:
|
|
186 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 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 opt_scalar_int_mode mode_iter;
|
|
208 FOR_EACH_MODE_FROM (mode_iter, smallest_int_mode_for_size (struct_bits))
|
|
209 {
|
|
210 scalar_int_mode mode = mode_iter.require ();
|
|
211 if (get_extraction_insn (insn, pattern, type, mode))
|
|
212 {
|
|
213 FOR_EACH_MODE_FROM (mode_iter, mode)
|
|
214 {
|
|
215 mode = mode_iter.require ();
|
131
|
216 if (maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (field_mode))
|
111
|
217 || TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
|
|
218 field_mode))
|
|
219 break;
|
|
220 get_extraction_insn (insn, pattern, type, mode);
|
|
221 }
|
|
222 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 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 return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
|
|
245 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 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 unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
|
|
264 + bitsize
|
|
265 + BITS_PER_UNIT - 1);
|
|
266 struct_bits -= struct_bits % BITS_PER_UNIT;
|
|
267 return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
|
|
268 struct_bits, field_mode);
|
|
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 can_extend_p (machine_mode to_mode, machine_mode from_mode,
|
|
277 int unsignedp)
|
|
278 {
|
|
279 if (unsignedp < 0 && targetm.have_ptr_extend ())
|
|
280 return targetm.code_for_ptr_extend;
|
|
281
|
|
282 convert_optab tab = unsignedp ? zext_optab : sext_optab;
|
|
283 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 can_float_p (machine_mode fltmode, machine_mode fixmode,
|
|
292 int unsignedp)
|
|
293 {
|
|
294 convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
|
|
295 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 can_fix_p (machine_mode fixmode, machine_mode fltmode,
|
|
307 int unsignedp, bool *truncp_ptr)
|
|
308 {
|
|
309 convert_optab tab;
|
|
310 enum insn_code icode;
|
|
311
|
|
312 tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
|
|
313 icode = convert_optab_handler (tab, fixmode, fltmode);
|
|
314 if (icode != CODE_FOR_nothing)
|
|
315 {
|
|
316 *truncp_ptr = false;
|
|
317 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 tab = unsignedp ? ufix_optab : sfix_optab;
|
|
324 icode = convert_optab_handler (tab, fixmode, fltmode);
|
|
325 if (icode != CODE_FOR_nothing
|
|
326 && optab_handler (ftrunc_optab, fltmode) != CODE_FOR_nothing)
|
|
327 {
|
|
328 *truncp_ptr = true;
|
|
329 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 can_conditionally_move_p (machine_mode mode)
|
|
345 {
|
|
346 return direct_optab_handler (movcc_optab, mode) != CODE_FOR_nothing;
|
|
347 }
|
|
348
|
131
|
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 qimode_for_vec_perm (machine_mode mode)
|
|
356 {
|
|
357 machine_mode qimode;
|
|
358 if (GET_MODE_INNER (mode) != QImode
|
|
359 && mode_for_vector (QImode, GET_MODE_SIZE (mode)).exists (&qimode)
|
|
360 && VECTOR_MODE_P (qimode))
|
|
361 return qimode;
|
|
362 return opt_machine_mode ();
|
|
363 }
|
|
364
|
|
365 /* Return true if selector SEL can be represented in the integer
|
|
366 equivalent of vector mode MODE. */
|
111
|
367
|
|
368 bool
|
131
|
369 selector_fits_mode_p (machine_mode mode, const vec_perm_indices &sel)
|
111
|
370 {
|
131
|
371 unsigned HOST_WIDE_INT mask = GET_MODE_MASK (GET_MODE_INNER (mode));
|
|
372 return (mask == HOST_WIDE_INT_M1U
|
|
373 || sel.all_in_range_p (0, mask + 1));
|
|
374 }
|
111
|
375
|
131
|
376 /* Return true if VEC_PERM_EXPRs with variable selector operands can be
|
|
377 expanded using SIMD extensions of the CPU. MODE is the mode of the
|
|
378 vectors being permuted. */
|
|
379
|
|
380 bool
|
|
381 can_vec_perm_var_p (machine_mode mode)
|
|
382 {
|
111
|
383 /* If the target doesn't implement a vector mode for the vector type,
|
|
384 then no operations are supported. */
|
|
385 if (!VECTOR_MODE_P (mode))
|
|
386 return false;
|
|
387
|
|
388 if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
|
|
389 return true;
|
|
390
|
|
391 /* We allow fallback to a QI vector mode, and adjust the mask. */
|
131
|
392 machine_mode qimode;
|
|
393 if (!qimode_for_vec_perm (mode).exists (&qimode)
|
|
394 || maybe_gt (GET_MODE_NUNITS (qimode), GET_MODE_MASK (QImode) + 1))
|
111
|
395 return false;
|
|
396
|
|
397 if (direct_optab_handler (vec_perm_optab, qimode) == CODE_FOR_nothing)
|
|
398 return false;
|
|
399
|
|
400 /* In order to support the lowering of variable permutations,
|
|
401 we need to support shifts and adds. */
|
131
|
402 if (GET_MODE_UNIT_SIZE (mode) > 2
|
|
403 && optab_handler (ashl_optab, mode) == CODE_FOR_nothing
|
|
404 && optab_handler (vashl_optab, mode) == CODE_FOR_nothing)
|
|
405 return false;
|
|
406 if (optab_handler (add_optab, qimode) == CODE_FOR_nothing)
|
|
407 return false;
|
111
|
408
|
|
409 return true;
|
|
410 }
|
|
411
|
131
|
412 /* Return true if the target directly supports VEC_PERM_EXPRs on vectors
|
|
413 of mode MODE using the selector SEL. ALLOW_VARIABLE_P is true if it
|
|
414 is acceptable to force the selector into a register and use a variable
|
|
415 permute (if the target supports that).
|
111
|
416
|
131
|
417 Note that additional permutations representing whole-vector shifts may
|
|
418 also be handled via the vec_shr optab, but only where the second input
|
|
419 vector is entirely constant zeroes; this case is not dealt with here. */
|
|
420
|
|
421 bool
|
|
422 can_vec_perm_const_p (machine_mode mode, const vec_perm_indices &sel,
|
|
423 bool allow_variable_p)
|
111
|
424 {
|
131
|
425 /* If the target doesn't implement a vector mode for the vector type,
|
|
426 then no operations are supported. */
|
|
427 if (!VECTOR_MODE_P (mode))
|
|
428 return false;
|
|
429
|
|
430 /* It's probably cheaper to test for the variable case first. */
|
|
431 if (allow_variable_p && selector_fits_mode_p (mode, sel))
|
111
|
432 {
|
131
|
433 if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing)
|
|
434 return true;
|
|
435
|
|
436 /* Unlike can_vec_perm_var_p, we don't need to test for optabs
|
|
437 related computing the QImode selector, since that happens at
|
|
438 compile time. */
|
|
439 machine_mode qimode;
|
|
440 if (qimode_for_vec_perm (mode).exists (&qimode))
|
|
441 {
|
|
442 vec_perm_indices qimode_indices;
|
|
443 qimode_indices.new_expanded_vector (sel, GET_MODE_UNIT_SIZE (mode));
|
|
444 if (selector_fits_mode_p (qimode, qimode_indices)
|
|
445 && (direct_optab_handler (vec_perm_optab, qimode)
|
|
446 != CODE_FOR_nothing))
|
|
447 return true;
|
|
448 }
|
111
|
449 }
|
131
|
450
|
|
451 if (targetm.vectorize.vec_perm_const != NULL)
|
|
452 {
|
|
453 if (targetm.vectorize.vec_perm_const (mode, NULL_RTX, NULL_RTX,
|
|
454 NULL_RTX, sel))
|
|
455 return true;
|
|
456
|
|
457 /* ??? For completeness, we ought to check the QImode version of
|
|
458 vec_perm_const_optab. But all users of this implicit lowering
|
|
459 feature implement the variable vec_perm_optab, and the ia64
|
|
460 port specifically doesn't want us to lower V2SF operations
|
|
461 into integer operations. */
|
|
462 }
|
|
463
|
|
464 return false;
|
111
|
465 }
|
|
466
|
|
467 /* Find a widening optab even if it doesn't widen as much as we want.
|
|
468 E.g. if from_mode is HImode, and to_mode is DImode, and there is no
|
131
|
469 direct HI->SI insn, then return SI->DI, if that exists. */
|
111
|
470
|
|
471 enum insn_code
|
|
472 find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
|
|
473 machine_mode from_mode,
|
|
474 machine_mode *found_mode)
|
|
475 {
|
131
|
476 machine_mode limit_mode = to_mode;
|
|
477 if (is_a <scalar_int_mode> (from_mode))
|
111
|
478 {
|
131
|
479 gcc_checking_assert (is_a <scalar_int_mode> (to_mode)
|
|
480 && known_lt (GET_MODE_PRECISION (from_mode),
|
|
481 GET_MODE_PRECISION (to_mode)));
|
|
482 /* The modes after FROM_MODE are all MODE_INT, so the only
|
|
483 MODE_PARTIAL_INT mode we consider is FROM_MODE itself.
|
|
484 If LIMIT_MODE is MODE_PARTIAL_INT, stop at the containing
|
|
485 MODE_INT. */
|
|
486 if (GET_MODE_CLASS (limit_mode) == MODE_PARTIAL_INT)
|
|
487 limit_mode = GET_MODE_WIDER_MODE (limit_mode).require ();
|
|
488 }
|
|
489 else
|
|
490 gcc_checking_assert (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
|
|
491 && from_mode < to_mode);
|
|
492 FOR_EACH_MODE (from_mode, from_mode, limit_mode)
|
|
493 {
|
|
494 enum insn_code handler = convert_optab_handler (op, to_mode, from_mode);
|
111
|
495
|
|
496 if (handler != CODE_FOR_nothing)
|
|
497 {
|
|
498 if (found_mode)
|
|
499 *found_mode = from_mode;
|
|
500 return handler;
|
|
501 }
|
|
502 }
|
|
503
|
|
504 return CODE_FOR_nothing;
|
|
505 }
|
|
506
|
|
507 /* Return non-zero if a highpart multiply is supported of can be synthisized.
|
|
508 For the benefit of expand_mult_highpart, the return value is 1 for direct,
|
|
509 2 for even/odd widening, and 3 for hi/lo widening. */
|
|
510
|
|
511 int
|
|
512 can_mult_highpart_p (machine_mode mode, bool uns_p)
|
|
513 {
|
|
514 optab op;
|
|
515
|
|
516 op = uns_p ? umul_highpart_optab : smul_highpart_optab;
|
|
517 if (optab_handler (op, mode) != CODE_FOR_nothing)
|
|
518 return 1;
|
|
519
|
|
520 /* If the mode is an integral vector, synth from widening operations. */
|
|
521 if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
|
|
522 return 0;
|
|
523
|
131
|
524 poly_int64 nunits = GET_MODE_NUNITS (mode);
|
111
|
525
|
|
526 op = uns_p ? vec_widen_umult_even_optab : vec_widen_smult_even_optab;
|
|
527 if (optab_handler (op, mode) != CODE_FOR_nothing)
|
|
528 {
|
|
529 op = uns_p ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab;
|
|
530 if (optab_handler (op, mode) != CODE_FOR_nothing)
|
|
531 {
|
131
|
532 /* The encoding has 2 interleaved stepped patterns. */
|
|
533 vec_perm_builder sel (nunits, 2, 3);
|
|
534 for (unsigned int i = 0; i < 6; ++i)
|
111
|
535 sel.quick_push (!BYTES_BIG_ENDIAN
|
|
536 + (i & ~1)
|
|
537 + ((i & 1) ? nunits : 0));
|
131
|
538 vec_perm_indices indices (sel, 2, nunits);
|
|
539 if (can_vec_perm_const_p (mode, indices))
|
111
|
540 return 2;
|
|
541 }
|
|
542 }
|
|
543
|
|
544 op = uns_p ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab;
|
|
545 if (optab_handler (op, mode) != CODE_FOR_nothing)
|
|
546 {
|
|
547 op = uns_p ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab;
|
|
548 if (optab_handler (op, mode) != CODE_FOR_nothing)
|
|
549 {
|
131
|
550 /* The encoding has a single stepped pattern. */
|
|
551 vec_perm_builder sel (nunits, 1, 3);
|
|
552 for (unsigned int i = 0; i < 3; ++i)
|
111
|
553 sel.quick_push (2 * i + (BYTES_BIG_ENDIAN ? 0 : 1));
|
131
|
554 vec_perm_indices indices (sel, 2, nunits);
|
|
555 if (can_vec_perm_const_p (mode, indices))
|
111
|
556 return 3;
|
|
557 }
|
|
558 }
|
|
559
|
|
560 return 0;
|
|
561 }
|
|
562
|
|
563 /* Return true if target supports vector masked load/store for mode. */
|
|
564
|
|
565 bool
|
|
566 can_vec_mask_load_store_p (machine_mode mode,
|
|
567 machine_mode mask_mode,
|
|
568 bool is_load)
|
|
569 {
|
|
570 optab op = is_load ? maskload_optab : maskstore_optab;
|
|
571 machine_mode vmode;
|
|
572
|
|
573 /* If mode is vector mode, check it directly. */
|
|
574 if (VECTOR_MODE_P (mode))
|
|
575 return convert_optab_handler (op, mode, mask_mode) != CODE_FOR_nothing;
|
|
576
|
|
577 /* Otherwise, return true if there is some vector mode with
|
|
578 the mask load/store supported. */
|
|
579
|
|
580 /* See if there is any chance the mask load or store might be
|
|
581 vectorized. If not, punt. */
|
|
582 scalar_mode smode;
|
|
583 if (!is_a <scalar_mode> (mode, &smode))
|
|
584 return false;
|
|
585
|
|
586 vmode = targetm.vectorize.preferred_simd_mode (smode);
|
|
587 if (!VECTOR_MODE_P (vmode))
|
|
588 return false;
|
|
589
|
|
590 if ((targetm.vectorize.get_mask_mode
|
|
591 (GET_MODE_NUNITS (vmode), GET_MODE_SIZE (vmode)).exists (&mask_mode))
|
|
592 && convert_optab_handler (op, vmode, mask_mode) != CODE_FOR_nothing)
|
|
593 return true;
|
|
594
|
131
|
595 auto_vector_sizes vector_sizes;
|
|
596 targetm.vectorize.autovectorize_vector_sizes (&vector_sizes);
|
|
597 for (unsigned int i = 0; i < vector_sizes.length (); ++i)
|
111
|
598 {
|
131
|
599 poly_uint64 cur = vector_sizes[i];
|
|
600 poly_uint64 nunits;
|
|
601 if (!multiple_p (cur, GET_MODE_SIZE (smode), &nunits))
|
111
|
602 continue;
|
|
603 if (mode_for_vector (smode, nunits).exists (&vmode)
|
|
604 && VECTOR_MODE_P (vmode)
|
|
605 && targetm.vectorize.get_mask_mode (nunits, cur).exists (&mask_mode)
|
|
606 && convert_optab_handler (op, vmode, mask_mode) != CODE_FOR_nothing)
|
|
607 return true;
|
|
608 }
|
|
609 return false;
|
|
610 }
|
|
611
|
|
612 /* Return true if there is a compare_and_swap pattern. */
|
|
613
|
|
614 bool
|
|
615 can_compare_and_swap_p (machine_mode mode, bool allow_libcall)
|
|
616 {
|
|
617 enum insn_code icode;
|
|
618
|
|
619 /* Check for __atomic_compare_and_swap. */
|
|
620 icode = direct_optab_handler (atomic_compare_and_swap_optab, mode);
|
|
621 if (icode != CODE_FOR_nothing)
|
|
622 return true;
|
|
623
|
|
624 /* Check for __sync_compare_and_swap. */
|
|
625 icode = optab_handler (sync_compare_and_swap_optab, mode);
|
|
626 if (icode != CODE_FOR_nothing)
|
|
627 return true;
|
|
628 if (allow_libcall && optab_libfunc (sync_compare_and_swap_optab, mode))
|
|
629 return true;
|
|
630
|
|
631 /* No inline compare and swap. */
|
|
632 return false;
|
|
633 }
|
|
634
|
|
635 /* Return true if an atomic exchange can be performed. */
|
|
636
|
|
637 bool
|
|
638 can_atomic_exchange_p (machine_mode mode, bool allow_libcall)
|
|
639 {
|
|
640 enum insn_code icode;
|
|
641
|
|
642 /* Check for __atomic_exchange. */
|
|
643 icode = direct_optab_handler (atomic_exchange_optab, mode);
|
|
644 if (icode != CODE_FOR_nothing)
|
|
645 return true;
|
|
646
|
|
647 /* Don't check __sync_test_and_set, as on some platforms that
|
|
648 has reduced functionality. Targets that really do support
|
|
649 a proper exchange should simply be updated to the __atomics. */
|
|
650
|
|
651 return can_compare_and_swap_p (mode, allow_libcall);
|
|
652 }
|
|
653
|
|
654 /* Return true if an atomic load can be performed without falling back to
|
|
655 a compare-and-swap. */
|
|
656
|
|
657 bool
|
|
658 can_atomic_load_p (machine_mode mode)
|
|
659 {
|
|
660 enum insn_code icode;
|
|
661
|
|
662 /* Does the target supports the load directly? */
|
|
663 icode = direct_optab_handler (atomic_load_optab, mode);
|
|
664 if (icode != CODE_FOR_nothing)
|
|
665 return true;
|
|
666
|
|
667 /* If the size of the object is greater than word size on this target,
|
|
668 then we assume that a load will not be atomic. Also see
|
|
669 expand_atomic_load. */
|
131
|
670 return known_le (GET_MODE_PRECISION (mode), BITS_PER_WORD);
|
111
|
671 }
|
|
672
|
|
673 /* Determine whether "1 << x" is relatively cheap in word_mode. */
|
|
674
|
|
675 bool
|
|
676 lshift_cheap_p (bool speed_p)
|
|
677 {
|
|
678 /* FIXME: This should be made target dependent via this "this_target"
|
|
679 mechanism, similar to e.g. can_copy_init_p in gcse.c. */
|
|
680 static bool init[2] = { false, false };
|
|
681 static bool cheap[2] = { true, true };
|
|
682
|
|
683 /* If the targer has no lshift in word_mode, the operation will most
|
|
684 probably not be cheap. ??? Does GCC even work for such targets? */
|
|
685 if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing)
|
|
686 return false;
|
|
687
|
|
688 if (!init[speed_p])
|
|
689 {
|
|
690 rtx reg = gen_raw_REG (word_mode, 10000);
|
|
691 int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg),
|
|
692 word_mode, speed_p);
|
|
693 cheap[speed_p] = cost < COSTS_N_INSNS (3);
|
|
694 init[speed_p] = true;
|
|
695 }
|
|
696
|
|
697 return cheap[speed_p];
|
|
698 }
|
131
|
699
|
|
700 /* Return true if optab OP supports at least one mode. */
|
|
701
|
|
702 static bool
|
|
703 supports_at_least_one_mode_p (optab op)
|
|
704 {
|
|
705 for (int i = 0; i < NUM_MACHINE_MODES; ++i)
|
|
706 if (direct_optab_handler (op, (machine_mode) i) != CODE_FOR_nothing)
|
|
707 return true;
|
|
708
|
|
709 return false;
|
|
710 }
|
|
711
|
|
712 /* Return true if vec_gather_load is available for at least one vector
|
|
713 mode. */
|
|
714
|
|
715 bool
|
|
716 supports_vec_gather_load_p ()
|
|
717 {
|
|
718 if (this_fn_optabs->supports_vec_gather_load_cached)
|
|
719 return this_fn_optabs->supports_vec_gather_load;
|
|
720
|
|
721 this_fn_optabs->supports_vec_gather_load_cached = true;
|
|
722
|
|
723 this_fn_optabs->supports_vec_gather_load
|
|
724 = supports_at_least_one_mode_p (gather_load_optab);
|
|
725
|
|
726 return this_fn_optabs->supports_vec_gather_load;
|
|
727 }
|
|
728
|
|
729 /* Return true if vec_scatter_store is available for at least one vector
|
|
730 mode. */
|
|
731
|
|
732 bool
|
|
733 supports_vec_scatter_store_p ()
|
|
734 {
|
|
735 if (this_fn_optabs->supports_vec_scatter_store_cached)
|
|
736 return this_fn_optabs->supports_vec_scatter_store;
|
|
737
|
|
738 this_fn_optabs->supports_vec_scatter_store_cached = true;
|
|
739
|
|
740 this_fn_optabs->supports_vec_scatter_store
|
|
741 = supports_at_least_one_mode_p (scatter_store_optab);
|
|
742
|
|
743 return this_fn_optabs->supports_vec_scatter_store;
|
|
744 }
|
|
745
|