Branch data Line data Source code
1 : : /* Tree-based 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 "rtl.h"
27 : : #include "tree.h"
28 : : #include "memmodel.h"
29 : : #include "optabs.h"
30 : : #include "optabs-tree.h"
31 : : #include "stor-layout.h"
32 : :
33 : : /* Return the optab used for computing the operation given by the tree code,
34 : : CODE and the tree EXP. This function is not always usable (for example, it
35 : : cannot give complete results for multiplication or division) but probably
36 : : ought to be relied on more widely throughout the expander. */
37 : : optab
38 : 7977656 : optab_for_tree_code (enum tree_code code, const_tree type,
39 : : enum optab_subtype subtype)
40 : : {
41 : 7977656 : bool trapv;
42 : 7977656 : switch (code)
43 : : {
44 : : case BIT_AND_EXPR:
45 : : return and_optab;
46 : :
47 : 192240 : case BIT_IOR_EXPR:
48 : 192240 : return ior_optab;
49 : :
50 : 4426 : case BIT_NOT_EXPR:
51 : 4426 : return one_cmpl_optab;
52 : :
53 : 38228 : case BIT_XOR_EXPR:
54 : 38228 : return xor_optab;
55 : :
56 : 583 : case MULT_HIGHPART_EXPR:
57 : 583 : return TYPE_UNSIGNED (type) ? umul_highpart_optab : smul_highpart_optab;
58 : :
59 : 102 : case CEIL_MOD_EXPR:
60 : 102 : case FLOOR_MOD_EXPR:
61 : 102 : case ROUND_MOD_EXPR:
62 : : /* {s,u}mod_optab implements TRUNC_MOD_EXPR. For scalar modes,
63 : : expansion has code to adjust TRUNC_MOD_EXPR into the desired other
64 : : modes, but for vector modes it does not. The adjustment code
65 : : should be instead emitted in tree-vect-patterns.cc. */
66 : 102 : if (VECTOR_TYPE_P (type))
67 : : return unknown_optab;
68 : : /* FALLTHRU */
69 : 2016 : case TRUNC_MOD_EXPR:
70 : 2016 : return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;
71 : :
72 : 0 : case CEIL_DIV_EXPR:
73 : 0 : case FLOOR_DIV_EXPR:
74 : 0 : case ROUND_DIV_EXPR:
75 : : /* {,u}{s,u}div_optab implements {TRUNC,EXACT}_DIV_EXPR or RDIV_EXPR.
76 : : For scalar modes, expansion has code to adjust TRUNC_DIV_EXPR
77 : : into the desired other modes, but for vector modes it does not.
78 : : The adjustment code should be instead emitted in
79 : : tree-vect-patterns.cc. */
80 : 0 : if (VECTOR_TYPE_P (type))
81 : : return unknown_optab;
82 : : /* FALLTHRU */
83 : 33767 : case RDIV_EXPR:
84 : 33767 : case TRUNC_DIV_EXPR:
85 : 33767 : case EXACT_DIV_EXPR:
86 : 33767 : if (TYPE_SATURATING (type))
87 : 0 : return TYPE_UNSIGNED (type) ? usdiv_optab : ssdiv_optab;
88 : 33767 : return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
89 : :
90 : 485411 : case LSHIFT_EXPR:
91 : 485411 : if (VECTOR_TYPE_P (type))
92 : : {
93 : 485376 : if (subtype == optab_vector)
94 : 227645 : return TYPE_SATURATING (type) ? unknown_optab : vashl_optab;
95 : :
96 : 257731 : gcc_assert (subtype == optab_scalar);
97 : : }
98 : 257766 : if (TYPE_SATURATING (type))
99 : 0 : return TYPE_UNSIGNED (type) ? usashl_optab : ssashl_optab;
100 : : return ashl_optab;
101 : :
102 : 138993 : case RSHIFT_EXPR:
103 : 138993 : if (VECTOR_TYPE_P (type))
104 : : {
105 : 138981 : if (subtype == optab_vector)
106 : 62390 : return TYPE_UNSIGNED (type) ? vlshr_optab : vashr_optab;
107 : :
108 : 76591 : gcc_assert (subtype == optab_scalar);
109 : : }
110 : 76603 : return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;
111 : :
112 : 534 : case LROTATE_EXPR:
113 : 534 : if (VECTOR_TYPE_P (type))
114 : : {
115 : 534 : if (subtype == optab_vector)
116 : : return vrotl_optab;
117 : :
118 : 231 : gcc_assert (subtype == optab_scalar);
119 : : }
120 : : return rotl_optab;
121 : :
122 : 7385 : case RROTATE_EXPR:
123 : 7385 : if (VECTOR_TYPE_P (type))
124 : : {
125 : 7385 : if (subtype == optab_vector)
126 : : return vrotr_optab;
127 : :
128 : 3688 : gcc_assert (subtype == optab_scalar);
129 : : }
130 : : return rotr_optab;
131 : :
132 : 58175 : case MAX_EXPR:
133 : 58175 : return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;
134 : :
135 : 37162 : case MIN_EXPR:
136 : 37162 : return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
137 : :
138 : 0 : case REALIGN_LOAD_EXPR:
139 : 0 : return vec_realign_load_optab;
140 : :
141 : 1443 : case WIDEN_SUM_EXPR:
142 : 1443 : return TYPE_UNSIGNED (type) ? usum_widen_optab : ssum_widen_optab;
143 : :
144 : 755 : case DOT_PROD_EXPR:
145 : 755 : {
146 : 755 : if (subtype == optab_vector_mixed_sign)
147 : : return usdot_prod_optab;
148 : :
149 : 523 : return (TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab);
150 : : }
151 : :
152 : 457 : case SAD_EXPR:
153 : 457 : return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;
154 : :
155 : 27275 : case WIDEN_MULT_PLUS_EXPR:
156 : 27275 : return (TYPE_UNSIGNED (type)
157 : 27275 : ? (TYPE_SATURATING (type)
158 : 19646 : ? usmadd_widen_optab : umadd_widen_optab)
159 : 7629 : : (TYPE_SATURATING (type)
160 : 7629 : ? ssmadd_widen_optab : smadd_widen_optab));
161 : :
162 : 488 : case WIDEN_MULT_MINUS_EXPR:
163 : 488 : return (TYPE_UNSIGNED (type)
164 : 488 : ? (TYPE_SATURATING (type)
165 : 405 : ? usmsub_widen_optab : umsub_widen_optab)
166 : 83 : : (TYPE_SATURATING (type)
167 : 83 : ? ssmsub_widen_optab : smsub_widen_optab));
168 : :
169 : 145336 : case VEC_WIDEN_MULT_HI_EXPR:
170 : 145336 : return (TYPE_UNSIGNED (type)
171 : 145336 : ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab);
172 : :
173 : 145328 : case VEC_WIDEN_MULT_LO_EXPR:
174 : 145328 : return (TYPE_UNSIGNED (type)
175 : 145328 : ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab);
176 : :
177 : 0 : case VEC_WIDEN_MULT_EVEN_EXPR:
178 : 0 : return (TYPE_UNSIGNED (type)
179 : 0 : ? vec_widen_umult_even_optab : vec_widen_smult_even_optab);
180 : :
181 : 0 : case VEC_WIDEN_MULT_ODD_EXPR:
182 : 0 : return (TYPE_UNSIGNED (type)
183 : 0 : ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab);
184 : :
185 : 8412 : case VEC_WIDEN_LSHIFT_HI_EXPR:
186 : 8412 : return (TYPE_UNSIGNED (type)
187 : 8412 : ? vec_widen_ushiftl_hi_optab : vec_widen_sshiftl_hi_optab);
188 : :
189 : 8412 : case VEC_WIDEN_LSHIFT_LO_EXPR:
190 : 8412 : return (TYPE_UNSIGNED (type)
191 : 8412 : ? vec_widen_ushiftl_lo_optab : vec_widen_sshiftl_lo_optab);
192 : :
193 : 34247 : case VEC_UNPACK_HI_EXPR:
194 : 34247 : return (TYPE_UNSIGNED (type)
195 : 34247 : ? vec_unpacku_hi_optab : vec_unpacks_hi_optab);
196 : :
197 : 34230 : case VEC_UNPACK_LO_EXPR:
198 : 34230 : return (TYPE_UNSIGNED (type)
199 : 34230 : ? vec_unpacku_lo_optab : vec_unpacks_lo_optab);
200 : :
201 : 6484 : case VEC_UNPACK_FLOAT_HI_EXPR:
202 : : /* The signedness is determined from input operand. */
203 : 6484 : return (TYPE_UNSIGNED (type)
204 : 6484 : ? vec_unpacku_float_hi_optab : vec_unpacks_float_hi_optab);
205 : :
206 : 6484 : case VEC_UNPACK_FLOAT_LO_EXPR:
207 : : /* The signedness is determined from input operand. */
208 : 6484 : return (TYPE_UNSIGNED (type)
209 : 6484 : ? vec_unpacku_float_lo_optab : vec_unpacks_float_lo_optab);
210 : :
211 : 437 : case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
212 : : /* The signedness is determined from output operand. */
213 : 437 : return (TYPE_UNSIGNED (type)
214 : 437 : ? vec_unpack_ufix_trunc_hi_optab
215 : : : vec_unpack_sfix_trunc_hi_optab);
216 : :
217 : 437 : case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
218 : : /* The signedness is determined from output operand. */
219 : 437 : return (TYPE_UNSIGNED (type)
220 : 437 : ? vec_unpack_ufix_trunc_lo_optab
221 : : : vec_unpack_sfix_trunc_lo_optab);
222 : :
223 : 39885 : case VEC_PACK_TRUNC_EXPR:
224 : 39885 : return vec_pack_trunc_optab;
225 : :
226 : 0 : case VEC_PACK_SAT_EXPR:
227 : 0 : return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
228 : :
229 : 936 : case VEC_PACK_FIX_TRUNC_EXPR:
230 : : /* The signedness is determined from output operand. */
231 : 936 : return (TYPE_UNSIGNED (type)
232 : 936 : ? vec_pack_ufix_trunc_optab : vec_pack_sfix_trunc_optab);
233 : :
234 : 143 : case VEC_PACK_FLOAT_EXPR:
235 : : /* The signedness is determined from input operand. */
236 : 143 : return (TYPE_UNSIGNED (type)
237 : 143 : ? vec_packu_float_optab : vec_packs_float_optab);
238 : :
239 : 0 : case VEC_DUPLICATE_EXPR:
240 : 0 : return vec_duplicate_optab;
241 : :
242 : 0 : case VEC_SERIES_EXPR:
243 : 0 : return vec_series_optab;
244 : :
245 : 6136117 : default:
246 : 6136117 : break;
247 : : }
248 : :
249 : 6136117 : trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
250 : 6136117 : switch (code)
251 : : {
252 : 4536043 : case POINTER_PLUS_EXPR:
253 : 4536043 : case PLUS_EXPR:
254 : 4536043 : if (TYPE_SATURATING (type))
255 : 0 : return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
256 : 4536043 : return trapv ? addv_optab : add_optab;
257 : :
258 : 791677 : case POINTER_DIFF_EXPR:
259 : 791677 : case MINUS_EXPR:
260 : 791677 : if (TYPE_SATURATING (type))
261 : 0 : return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
262 : 791677 : return trapv ? subv_optab : sub_optab;
263 : :
264 : 649395 : case MULT_EXPR:
265 : 649395 : if (TYPE_SATURATING (type))
266 : 0 : return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
267 : 649395 : return trapv ? smulv_optab : smul_optab;
268 : :
269 : 54833 : case NEGATE_EXPR:
270 : 54833 : if (TYPE_SATURATING (type))
271 : 0 : return TYPE_UNSIGNED (type) ? usneg_optab : ssneg_optab;
272 : 54833 : return trapv ? negv_optab : neg_optab;
273 : :
274 : 737 : case ABS_EXPR:
275 : 737 : return trapv ? absv_optab : abs_optab;
276 : :
277 : : case ABSU_EXPR:
278 : : return abs_optab;
279 : : default:
280 : : return unknown_optab;
281 : : }
282 : : }
283 : :
284 : : /* Check whether an operation represented by CODE is a 'half' widening operation
285 : : in which the input vector type has half the number of bits of the output
286 : : vector type e.g. V8QI->V8HI.
287 : :
288 : : This is handled by widening the inputs using NOP_EXPRs then using a
289 : : non-widening stmt e.g. MINUS_EXPR. RTL fusing converts these to the widening
290 : : hardware instructions if supported.
291 : :
292 : : The more typical case (handled in supportable_widening_operation) is where
293 : : the input vector type has the same number of bits as the output vector type.
294 : : In this case half the elements of the input vectors must be processed at a
295 : : time into respective vector outputs with elements twice as wide i.e. a
296 : : 'hi'/'lo' pair using codes such as VEC_WIDEN_MINUS_HI/LO.
297 : :
298 : : Supported widening operations:
299 : : WIDEN_MULT_EXPR
300 : : WIDEN_LSHIFT_EXPR
301 : :
302 : : Output:
303 : : - CODE1 - The non-widened code, which will be used after the inputs are
304 : : converted to the wide type. */
305 : : bool
306 : 237 : supportable_half_widening_operation (enum tree_code code, tree vectype_out,
307 : : tree vectype_in, enum tree_code *code1)
308 : : {
309 : 237 : machine_mode m1,m2;
310 : 237 : enum tree_code dummy_code;
311 : 237 : optab op;
312 : :
313 : 237 : gcc_assert (VECTOR_TYPE_P (vectype_out) && VECTOR_TYPE_P (vectype_in));
314 : :
315 : 237 : m1 = TYPE_MODE (vectype_out);
316 : 237 : m2 = TYPE_MODE (vectype_in);
317 : :
318 : 237 : if (!VECTOR_MODE_P (m1) || !VECTOR_MODE_P (m2))
319 : : return false;
320 : :
321 : 237 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in),
322 : 474 : TYPE_VECTOR_SUBPARTS (vectype_out)))
323 : : return false;
324 : :
325 : 237 : switch (code)
326 : : {
327 : 0 : case WIDEN_LSHIFT_EXPR:
328 : 0 : *code1 = LSHIFT_EXPR;
329 : 0 : break;
330 : 237 : case WIDEN_MULT_EXPR:
331 : 237 : *code1 = MULT_EXPR;
332 : 237 : break;
333 : : default:
334 : : return false;
335 : : }
336 : :
337 : 237 : if (!supportable_convert_operation (NOP_EXPR, vectype_out, vectype_in,
338 : : &dummy_code))
339 : : return false;
340 : :
341 : 205 : op = optab_for_tree_code (*code1, vectype_out, optab_vector);
342 : 205 : return (optab_handler (op, TYPE_MODE (vectype_out)) != CODE_FOR_nothing);
343 : : }
344 : :
345 : : /* Function supportable_convert_operation
346 : :
347 : : Check whether an operation represented by the code CODE is a
348 : : convert operation that is supported by the target platform in
349 : : vector form (i.e., when operating on arguments of type VECTYPE_IN
350 : : producing a result of type VECTYPE_OUT).
351 : :
352 : : Convert operations we currently support directly are FIX_TRUNC and FLOAT.
353 : : This function checks if these operations are supported
354 : : by the target platform directly (via vector tree-codes).
355 : :
356 : : Output:
357 : : - CODE1 is code of vector operation to be used when
358 : : vectorizing the operation, if available. */
359 : :
360 : : bool
361 : 69803 : supportable_convert_operation (enum tree_code code,
362 : : tree vectype_out, tree vectype_in,
363 : : enum tree_code *code1)
364 : : {
365 : 69803 : machine_mode m1,m2;
366 : 69803 : bool truncp;
367 : :
368 : 69803 : gcc_assert (VECTOR_TYPE_P (vectype_out) && VECTOR_TYPE_P (vectype_in));
369 : :
370 : 69803 : m1 = TYPE_MODE (vectype_out);
371 : 69803 : m2 = TYPE_MODE (vectype_in);
372 : :
373 : 69803 : if (!VECTOR_MODE_P (m1) || !VECTOR_MODE_P (m2))
374 : : return false;
375 : :
376 : : /* First check if we can done conversion directly. */
377 : 69741 : if ((code == FIX_TRUNC_EXPR
378 : 1137 : && can_fix_p (m1,m2,TYPE_UNSIGNED (vectype_out), &truncp)
379 : : != CODE_FOR_nothing)
380 : 69980 : || (code == FLOAT_EXPR
381 : 5261 : && can_float_p (m1,m2,TYPE_UNSIGNED (vectype_in))
382 : : != CODE_FOR_nothing))
383 : : {
384 : 5912 : *code1 = code;
385 : 5912 : return true;
386 : : }
387 : :
388 : 127658 : if (GET_MODE_UNIT_PRECISION (m1) > GET_MODE_UNIT_PRECISION (m2)
389 : 63829 : && can_extend_p (m1, m2, TYPE_UNSIGNED (vectype_in)))
390 : : {
391 : 7444 : *code1 = code;
392 : 7444 : return true;
393 : : }
394 : :
395 : 112770 : if (GET_MODE_UNIT_PRECISION (m1) < GET_MODE_UNIT_PRECISION (m2)
396 : 60853 : && convert_optab_handler (trunc_optab, m1, m2) != CODE_FOR_nothing)
397 : : {
398 : 199 : *code1 = code;
399 : 199 : return true;
400 : : }
401 : :
402 : : return false;
403 : : }
404 : :
405 : : /* Return true iff vec_cmp_optab/vec_cmpu_optab can handle a vector comparison
406 : : for code CODE, comparing operands of type VALUE_TYPE and producing a result
407 : : of type MASK_TYPE. */
408 : :
409 : : static bool
410 : 1076318 : vec_cmp_icode_p (tree value_type, tree mask_type, enum tree_code code)
411 : : {
412 : 1076318 : enum rtx_code rcode = get_rtx_code_1 (code, TYPE_UNSIGNED (value_type));
413 : 1076318 : if (rcode == UNKNOWN)
414 : : return false;
415 : :
416 : 1076304 : return can_vec_cmp_compare_p (rcode, TYPE_MODE (value_type),
417 : 2152608 : TYPE_MODE (mask_type));
418 : : }
419 : :
420 : : /* Return true iff vec_cmpeq_optab can handle a vector comparison for code
421 : : CODE, comparing operands of type VALUE_TYPE and producing a result of type
422 : : MASK_TYPE. */
423 : :
424 : : static bool
425 : 308958 : vec_cmp_eq_icode_p (tree value_type, tree mask_type, enum tree_code code)
426 : : {
427 : 308958 : if (code != EQ_EXPR && code != NE_EXPR)
428 : : return false;
429 : :
430 : 158944 : return get_vec_cmp_eq_icode (TYPE_MODE (value_type), TYPE_MODE (mask_type))
431 : 158944 : != CODE_FOR_nothing;
432 : : }
433 : :
434 : : /* Return TRUE if appropriate vector insn is available
435 : : for vector comparison expr with vector type VALUE_TYPE
436 : : and resulting mask with MASK_TYPE. */
437 : :
438 : : bool
439 : 1076318 : expand_vec_cmp_expr_p (tree value_type, tree mask_type, enum tree_code code)
440 : : {
441 : 1076318 : return vec_cmp_icode_p (value_type, mask_type, code)
442 : 1076318 : || vec_cmp_eq_icode_p (value_type, mask_type, code);
443 : : }
444 : :
445 : : /* Return true iff vcond_optab/vcondu_optab can handle a vector
446 : : comparison for code CODE, comparing operands of type CMP_OP_TYPE and
447 : : producing a result of type VALUE_TYPE. */
448 : :
449 : : static bool
450 : 61705 : vcond_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
451 : : {
452 : 61705 : enum rtx_code rcode = get_rtx_code_1 (code, TYPE_UNSIGNED (cmp_op_type));
453 : 61705 : if (rcode == UNKNOWN)
454 : : return false;
455 : :
456 : 61705 : return can_vcond_compare_p (rcode, TYPE_MODE (value_type),
457 : 123410 : TYPE_MODE (cmp_op_type));
458 : : }
459 : :
460 : : /* Return true iff vcondeq_optab can handle a vector comparison for code CODE,
461 : : comparing operands of type CMP_OP_TYPE and producing a result of type
462 : : VALUE_TYPE. */
463 : :
464 : : static bool
465 : 37477 : vcond_eq_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
466 : : {
467 : 37477 : if (code != EQ_EXPR && code != NE_EXPR)
468 : : return false;
469 : :
470 : 12438 : return get_vcond_eq_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type))
471 : 12438 : != CODE_FOR_nothing;
472 : : }
473 : :
474 : : /* Return TRUE iff, appropriate vector insns are available
475 : : for vector cond expr with vector type VALUE_TYPE and a comparison
476 : : with operand vector types in CMP_OP_TYPE. */
477 : :
478 : : bool
479 : 77891 : expand_vec_cond_expr_p (tree value_type, tree cmp_op_type, enum tree_code code)
480 : : {
481 : 77891 : machine_mode value_mode = TYPE_MODE (value_type);
482 : 77891 : machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
483 : 77891 : if (VECTOR_BOOLEAN_TYPE_P (cmp_op_type)
484 : 110065 : && get_vcond_mask_icode (TYPE_MODE (value_type),
485 : 16087 : TYPE_MODE (cmp_op_type)) != CODE_FOR_nothing)
486 : : return true;
487 : :
488 : 189414 : if (maybe_ne (GET_MODE_NUNITS (value_mode), GET_MODE_NUNITS (cmp_op_mode)))
489 : : return false;
490 : :
491 : 62996 : if (TREE_CODE_CLASS (code) != tcc_comparison)
492 : : /* This may happen, for example, if code == SSA_NAME, in which case we
493 : : cannot be certain whether a vector insn is available. */
494 : : return false;
495 : :
496 : 61705 : return vcond_icode_p (value_type, cmp_op_type, code)
497 : 61705 : || vcond_eq_icode_p (value_type, cmp_op_type, code);
498 : : }
499 : :
500 : : /* Use the current target and options to initialize
501 : : TREE_OPTIMIZATION_OPTABS (OPTNODE). */
502 : :
503 : : void
504 : 1604138 : init_tree_optimization_optabs (tree optnode)
505 : : {
506 : : /* Quick exit if we have already computed optabs for this target. */
507 : 1604138 : if (TREE_OPTIMIZATION_BASE_OPTABS (optnode) == this_target_optabs)
508 : : return;
509 : :
510 : : /* Forget any previous information and set up for the current target. */
511 : 24823 : TREE_OPTIMIZATION_BASE_OPTABS (optnode) = this_target_optabs;
512 : 24823 : struct target_optabs *tmp_optabs = (struct target_optabs *)
513 : 24823 : TREE_OPTIMIZATION_OPTABS (optnode);
514 : 24823 : if (tmp_optabs)
515 : 274 : memset (tmp_optabs, 0, sizeof (struct target_optabs));
516 : : else
517 : 24549 : tmp_optabs = ggc_cleared_alloc<target_optabs> ();
518 : :
519 : : /* Generate a new set of optabs into tmp_optabs. */
520 : 24823 : init_all_optabs (tmp_optabs);
521 : :
522 : : /* If the optabs changed, record it. */
523 : 24823 : if (memcmp (tmp_optabs, this_target_optabs, sizeof (struct target_optabs)))
524 : 361 : TREE_OPTIMIZATION_OPTABS (optnode) = tmp_optabs;
525 : : else
526 : : {
527 : 24462 : TREE_OPTIMIZATION_OPTABS (optnode) = NULL;
528 : 24462 : ggc_free (tmp_optabs);
529 : : }
530 : : }
531 : :
532 : : /* Return TRUE if the target has support for vector right shift of an
533 : : operand of type TYPE. If OT_TYPE is OPTAB_DEFAULT, check for existence
534 : : of a shift by either a scalar or a vector. Otherwise, check only
535 : : for a shift that matches OT_TYPE. */
536 : :
537 : : bool
538 : 29662 : target_supports_op_p (tree type, enum tree_code code,
539 : : enum optab_subtype ot_subtype)
540 : : {
541 : 29662 : optab ot = optab_for_tree_code (code, type, ot_subtype);
542 : 29662 : return (ot != unknown_optab
543 : 29662 : && optab_handler (ot, TYPE_MODE (type)) != CODE_FOR_nothing);
544 : : }
545 : :
546 : : /* Return true if the target has support for masked load/store.
547 : : We can support masked load/store by either mask{load,store}
548 : : or mask_len_{load,store}.
549 : : This helper function checks whether target supports masked
550 : : load/store and return corresponding IFN in the last argument
551 : : (IFN_MASK_{LOAD,STORE} or IFN_MASK_LEN_{LOAD,STORE}). */
552 : :
553 : : static bool
554 : 31780 : target_supports_mask_load_store_p (machine_mode mode, machine_mode mask_mode,
555 : : bool is_load, internal_fn *ifn)
556 : : {
557 : 31780 : optab op = is_load ? maskload_optab : maskstore_optab;
558 : 10801 : optab len_op = is_load ? mask_len_load_optab : mask_len_store_optab;
559 : 31780 : if (convert_optab_handler (op, mode, mask_mode) != CODE_FOR_nothing)
560 : : {
561 : 8329 : if (ifn)
562 : 2831 : *ifn = is_load ? IFN_MASK_LOAD : IFN_MASK_STORE;
563 : 8329 : return true;
564 : : }
565 : 23451 : else if (convert_optab_handler (len_op, mode, mask_mode) != CODE_FOR_nothing)
566 : : {
567 : 0 : if (ifn)
568 : 0 : *ifn = is_load ? IFN_MASK_LEN_LOAD : IFN_MASK_LEN_STORE;
569 : 0 : return true;
570 : : }
571 : : return false;
572 : : }
573 : :
574 : : /* Return true if target supports vector masked load/store for mode.
575 : : An additional output in the last argument which is the IFN pointer.
576 : : We set IFN as MASK_{LOAD,STORE} or MASK_LEN_{LOAD,STORE} according
577 : : which optab is supported in the target. */
578 : :
579 : : bool
580 : 15566 : can_vec_mask_load_store_p (machine_mode mode,
581 : : machine_mode mask_mode,
582 : : bool is_load,
583 : : internal_fn *ifn)
584 : : {
585 : 15566 : machine_mode vmode;
586 : :
587 : : /* If mode is vector mode, check it directly. */
588 : 15566 : if (VECTOR_MODE_P (mode))
589 : 5670 : return target_supports_mask_load_store_p (mode, mask_mode, is_load, ifn);
590 : :
591 : : /* Otherwise, return true if there is some vector mode with
592 : : the mask load/store supported. */
593 : :
594 : : /* See if there is any chance the mask load or store might be
595 : : vectorized. If not, punt. */
596 : 9896 : scalar_mode smode;
597 : 9896 : if (!is_a <scalar_mode> (mode, &smode))
598 : : return false;
599 : :
600 : 9896 : vmode = targetm.vectorize.preferred_simd_mode (smode);
601 : 1824 : if (VECTOR_MODE_P (vmode)
602 : 9748 : && targetm.vectorize.get_mask_mode (vmode).exists (&mask_mode)
603 : 19644 : && target_supports_mask_load_store_p (vmode, mask_mode, is_load, ifn))
604 : 2722 : return true;
605 : :
606 : 7174 : auto_vector_modes vector_modes;
607 : 7174 : targetm.vectorize.autovectorize_vector_modes (&vector_modes, true);
608 : 41936 : for (machine_mode base_mode : vector_modes)
609 : 20414 : if (related_vector_mode (base_mode, smode).exists (&vmode)
610 : 36776 : && targetm.vectorize.get_mask_mode (vmode).exists (&mask_mode)
611 : 16362 : && target_supports_mask_load_store_p (vmode, mask_mode, is_load, ifn))
612 : 0 : return true;
613 : : return false;
614 : 7174 : }
615 : :
616 : : /* Return true if the target has support for len load/store.
617 : : We can support len load/store by either len_{load,store}
618 : : or mask_len_{load,store}.
619 : : This helper function checks whether target supports len
620 : : load/store and return corresponding IFN in the last argument
621 : : (IFN_LEN_{LOAD,STORE} or IFN_MASK_LEN_{LOAD,STORE}). */
622 : :
623 : : static bool
624 : 98 : target_supports_len_load_store_p (machine_mode mode, bool is_load,
625 : : internal_fn *ifn)
626 : : {
627 : 98 : optab op = is_load ? len_load_optab : len_store_optab;
628 : 36 : optab masked_op = is_load ? mask_len_load_optab : mask_len_store_optab;
629 : :
630 : 98 : if (direct_optab_handler (op, mode))
631 : : {
632 : 0 : if (ifn)
633 : 0 : *ifn = is_load ? IFN_LEN_LOAD : IFN_LEN_STORE;
634 : 0 : return true;
635 : : }
636 : 98 : machine_mode mask_mode;
637 : 196 : if (targetm.vectorize.get_mask_mode (mode).exists (&mask_mode)
638 : 98 : && convert_optab_handler (masked_op, mode, mask_mode) != CODE_FOR_nothing)
639 : : {
640 : 0 : if (ifn)
641 : 0 : *ifn = is_load ? IFN_MASK_LEN_LOAD : IFN_MASK_LEN_STORE;
642 : 0 : return true;
643 : : }
644 : : return false;
645 : : }
646 : :
647 : : /* If target supports vector load/store with length for vector mode MODE,
648 : : return the corresponding vector mode, otherwise return opt_machine_mode ().
649 : : There are two flavors for vector load/store with length, one is to measure
650 : : length with bytes, the other is to measure length with lanes.
651 : : As len_{load,store} optabs point out, for the flavor with bytes, we use
652 : : VnQI to wrap the other supportable same size vector modes.
653 : : An additional output in the last argument which is the IFN pointer.
654 : : We set IFN as LEN_{LOAD,STORE} or MASK_LEN_{LOAD,STORE} according
655 : : which optab is supported in the target. */
656 : :
657 : : opt_machine_mode
658 : 49 : get_len_load_store_mode (machine_mode mode, bool is_load, internal_fn *ifn)
659 : : {
660 : 49 : gcc_assert (VECTOR_MODE_P (mode));
661 : :
662 : : /* Check if length in lanes supported for this mode directly. */
663 : 49 : if (target_supports_len_load_store_p (mode, is_load, ifn))
664 : 0 : return mode;
665 : :
666 : : /* Check if length in bytes supported for same vector size VnQI. */
667 : 49 : machine_mode vmode;
668 : 98 : poly_uint64 nunits = GET_MODE_SIZE (mode);
669 : 49 : if (related_vector_mode (mode, QImode, nunits).exists (&vmode)
670 : 49 : && target_supports_len_load_store_p (vmode, is_load, ifn))
671 : 0 : return vmode;
672 : :
673 : 49 : return opt_machine_mode ();
674 : : }
|