xref: /netbsd-src/external/gpl3/gcc/dist/gcc/optabs-tree.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Tree-based target query functions relating to optabs
2    Copyright (C) 1987-2022 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
optab_for_tree_code(enum tree_code code,const_tree type,enum optab_subtype subtype)38 optab_for_tree_code (enum tree_code code, const_tree type,
39 		     enum optab_subtype subtype)
40 {
41   bool trapv;
42   switch (code)
43     {
44     case BIT_AND_EXPR:
45       return and_optab;
46 
47     case BIT_IOR_EXPR:
48       return ior_optab;
49 
50     case BIT_NOT_EXPR:
51       return one_cmpl_optab;
52 
53     case BIT_XOR_EXPR:
54       return xor_optab;
55 
56     case MULT_HIGHPART_EXPR:
57       return TYPE_UNSIGNED (type) ? umul_highpart_optab : smul_highpart_optab;
58 
59     case CEIL_MOD_EXPR:
60     case FLOOR_MOD_EXPR:
61     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       if (TREE_CODE (type) == VECTOR_TYPE)
67 	return unknown_optab;
68       /* FALLTHRU */
69     case TRUNC_MOD_EXPR:
70       return TYPE_UNSIGNED (type) ? umod_optab : smod_optab;
71 
72     case CEIL_DIV_EXPR:
73     case FLOOR_DIV_EXPR:
74     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       if (TREE_CODE (type) == VECTOR_TYPE)
81 	return unknown_optab;
82       /* FALLTHRU */
83     case RDIV_EXPR:
84     case TRUNC_DIV_EXPR:
85     case EXACT_DIV_EXPR:
86       if (TYPE_SATURATING (type))
87 	return TYPE_UNSIGNED (type) ? usdiv_optab : ssdiv_optab;
88       return TYPE_UNSIGNED (type) ? udiv_optab : sdiv_optab;
89 
90     case LSHIFT_EXPR:
91       if (TREE_CODE (type) == VECTOR_TYPE)
92 	{
93 	  if (subtype == optab_vector)
94 	    return TYPE_SATURATING (type) ? unknown_optab : vashl_optab;
95 
96 	  gcc_assert (subtype == optab_scalar);
97 	}
98       if (TYPE_SATURATING (type))
99 	return TYPE_UNSIGNED (type) ? usashl_optab : ssashl_optab;
100       return ashl_optab;
101 
102     case RSHIFT_EXPR:
103       if (TREE_CODE (type) == VECTOR_TYPE)
104 	{
105 	  if (subtype == optab_vector)
106 	    return TYPE_UNSIGNED (type) ? vlshr_optab : vashr_optab;
107 
108 	  gcc_assert (subtype == optab_scalar);
109 	}
110       return TYPE_UNSIGNED (type) ? lshr_optab : ashr_optab;
111 
112     case LROTATE_EXPR:
113       if (TREE_CODE (type) == VECTOR_TYPE)
114 	{
115 	  if (subtype == optab_vector)
116 	    return vrotl_optab;
117 
118 	  gcc_assert (subtype == optab_scalar);
119 	}
120       return rotl_optab;
121 
122     case RROTATE_EXPR:
123       if (TREE_CODE (type) == VECTOR_TYPE)
124 	{
125 	  if (subtype == optab_vector)
126 	    return vrotr_optab;
127 
128 	  gcc_assert (subtype == optab_scalar);
129 	}
130       return rotr_optab;
131 
132     case MAX_EXPR:
133       return TYPE_UNSIGNED (type) ? umax_optab : smax_optab;
134 
135     case MIN_EXPR:
136       return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
137 
138     case REALIGN_LOAD_EXPR:
139       return vec_realign_load_optab;
140 
141     case WIDEN_SUM_EXPR:
142       return TYPE_UNSIGNED (type) ? usum_widen_optab : ssum_widen_optab;
143 
144     case DOT_PROD_EXPR:
145       {
146 	if (subtype == optab_vector_mixed_sign)
147 	  return usdot_prod_optab;
148 
149 	return (TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab);
150       }
151 
152     case SAD_EXPR:
153       return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;
154 
155     case WIDEN_MULT_PLUS_EXPR:
156       return (TYPE_UNSIGNED (type)
157 	      ? (TYPE_SATURATING (type)
158 		 ? usmadd_widen_optab : umadd_widen_optab)
159 	      : (TYPE_SATURATING (type)
160 		 ? ssmadd_widen_optab : smadd_widen_optab));
161 
162     case WIDEN_MULT_MINUS_EXPR:
163       return (TYPE_UNSIGNED (type)
164 	      ? (TYPE_SATURATING (type)
165 		 ? usmsub_widen_optab : umsub_widen_optab)
166 	      : (TYPE_SATURATING (type)
167 		 ? ssmsub_widen_optab : smsub_widen_optab));
168 
169     case VEC_WIDEN_MULT_HI_EXPR:
170       return (TYPE_UNSIGNED (type)
171 	      ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab);
172 
173     case VEC_WIDEN_MULT_LO_EXPR:
174       return (TYPE_UNSIGNED (type)
175 	      ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab);
176 
177     case VEC_WIDEN_MULT_EVEN_EXPR:
178       return (TYPE_UNSIGNED (type)
179 	      ? vec_widen_umult_even_optab : vec_widen_smult_even_optab);
180 
181     case VEC_WIDEN_MULT_ODD_EXPR:
182       return (TYPE_UNSIGNED (type)
183 	      ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab);
184 
185     case VEC_WIDEN_LSHIFT_HI_EXPR:
186       return (TYPE_UNSIGNED (type)
187 	      ? vec_widen_ushiftl_hi_optab : vec_widen_sshiftl_hi_optab);
188 
189     case VEC_WIDEN_LSHIFT_LO_EXPR:
190       return (TYPE_UNSIGNED (type)
191 	      ? vec_widen_ushiftl_lo_optab : vec_widen_sshiftl_lo_optab);
192 
193     case VEC_WIDEN_PLUS_LO_EXPR:
194       return (TYPE_UNSIGNED (type)
195 	      ? vec_widen_uaddl_lo_optab : vec_widen_saddl_lo_optab);
196 
197     case VEC_WIDEN_PLUS_HI_EXPR:
198       return (TYPE_UNSIGNED (type)
199 	      ? vec_widen_uaddl_hi_optab : vec_widen_saddl_hi_optab);
200 
201     case VEC_WIDEN_MINUS_LO_EXPR:
202       return (TYPE_UNSIGNED (type)
203 	      ? vec_widen_usubl_lo_optab : vec_widen_ssubl_lo_optab);
204 
205     case VEC_WIDEN_MINUS_HI_EXPR:
206       return (TYPE_UNSIGNED (type)
207 	      ? vec_widen_usubl_hi_optab : vec_widen_ssubl_hi_optab);
208 
209     case VEC_UNPACK_HI_EXPR:
210       return (TYPE_UNSIGNED (type)
211 	      ? vec_unpacku_hi_optab : vec_unpacks_hi_optab);
212 
213     case VEC_UNPACK_LO_EXPR:
214       return (TYPE_UNSIGNED (type)
215 	      ? vec_unpacku_lo_optab : vec_unpacks_lo_optab);
216 
217     case VEC_UNPACK_FLOAT_HI_EXPR:
218       /* The signedness is determined from input operand.  */
219       return (TYPE_UNSIGNED (type)
220 	      ? vec_unpacku_float_hi_optab : vec_unpacks_float_hi_optab);
221 
222     case VEC_UNPACK_FLOAT_LO_EXPR:
223       /* The signedness is determined from input operand.  */
224       return (TYPE_UNSIGNED (type)
225 	      ? vec_unpacku_float_lo_optab : vec_unpacks_float_lo_optab);
226 
227     case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
228       /* The signedness is determined from output operand.  */
229       return (TYPE_UNSIGNED (type)
230 	      ? vec_unpack_ufix_trunc_hi_optab
231 	      : vec_unpack_sfix_trunc_hi_optab);
232 
233     case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
234       /* The signedness is determined from output operand.  */
235       return (TYPE_UNSIGNED (type)
236 	      ? vec_unpack_ufix_trunc_lo_optab
237 	      : vec_unpack_sfix_trunc_lo_optab);
238 
239     case VEC_PACK_TRUNC_EXPR:
240       return vec_pack_trunc_optab;
241 
242     case VEC_PACK_SAT_EXPR:
243       return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
244 
245     case VEC_PACK_FIX_TRUNC_EXPR:
246       /* The signedness is determined from output operand.  */
247       return (TYPE_UNSIGNED (type)
248 	      ? vec_pack_ufix_trunc_optab : vec_pack_sfix_trunc_optab);
249 
250     case VEC_PACK_FLOAT_EXPR:
251       /* The signedness is determined from input operand.  */
252       return (TYPE_UNSIGNED (type)
253 	      ? vec_packu_float_optab : vec_packs_float_optab);
254 
255     case VEC_DUPLICATE_EXPR:
256       return vec_duplicate_optab;
257 
258     case VEC_SERIES_EXPR:
259       return vec_series_optab;
260 
261     default:
262       break;
263     }
264 
265   trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
266   switch (code)
267     {
268     case POINTER_PLUS_EXPR:
269     case PLUS_EXPR:
270       if (TYPE_SATURATING (type))
271 	return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
272       return trapv ? addv_optab : add_optab;
273 
274     case POINTER_DIFF_EXPR:
275     case MINUS_EXPR:
276       if (TYPE_SATURATING (type))
277 	return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
278       return trapv ? subv_optab : sub_optab;
279 
280     case MULT_EXPR:
281       if (TYPE_SATURATING (type))
282 	return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
283       return trapv ? smulv_optab : smul_optab;
284 
285     case NEGATE_EXPR:
286       if (TYPE_SATURATING (type))
287 	return TYPE_UNSIGNED (type) ? usneg_optab : ssneg_optab;
288       return trapv ? negv_optab : neg_optab;
289 
290     case ABS_EXPR:
291       return trapv ? absv_optab : abs_optab;
292 
293     case ABSU_EXPR:
294       return abs_optab;
295     default:
296       return unknown_optab;
297     }
298 }
299 
300 /* Check whether an operation represented by CODE is a 'half' widening operation
301    in which the input vector type has half the number of bits of the output
302    vector type e.g. V8QI->V8HI.
303 
304    This is handled by widening the inputs using NOP_EXPRs then using a
305    non-widening stmt e.g. MINUS_EXPR.  RTL fusing converts these to the widening
306    hardware instructions if supported.
307 
308    The more typical case (handled in supportable_widening_operation) is where
309    the input vector type has the same number of bits as the output vector type.
310    In this case half the elements of the input vectors must be processed at a
311    time into respective vector outputs with elements twice as wide i.e. a
312    'hi'/'lo' pair using codes such as VEC_WIDEN_MINUS_HI/LO.
313 
314    Supported widening operations:
315     WIDEN_MINUS_EXPR
316     WIDEN_PLUS_EXPR
317     WIDEN_MULT_EXPR
318     WIDEN_LSHIFT_EXPR
319 
320    Output:
321    - CODE1 - The non-widened code, which will be used after the inputs are
322      converted to the wide type.  */
323 bool
supportable_half_widening_operation(enum tree_code code,tree vectype_out,tree vectype_in,enum tree_code * code1)324 supportable_half_widening_operation (enum tree_code code, tree vectype_out,
325 				     tree vectype_in, enum tree_code *code1)
326 {
327   machine_mode m1,m2;
328   enum tree_code dummy_code;
329   optab op;
330 
331   gcc_assert (VECTOR_TYPE_P (vectype_out) && VECTOR_TYPE_P (vectype_in));
332 
333   m1 = TYPE_MODE (vectype_out);
334   m2 = TYPE_MODE (vectype_in);
335 
336   if (!VECTOR_MODE_P (m1) || !VECTOR_MODE_P (m2))
337     return false;
338 
339   if (maybe_ne (TYPE_VECTOR_SUBPARTS (vectype_in),
340 		  TYPE_VECTOR_SUBPARTS (vectype_out)))
341     return false;
342 
343   switch (code)
344     {
345     case WIDEN_LSHIFT_EXPR:
346       *code1 = LSHIFT_EXPR;
347       break;
348     case WIDEN_MINUS_EXPR:
349       *code1 = MINUS_EXPR;
350       break;
351     case WIDEN_PLUS_EXPR:
352       *code1 = PLUS_EXPR;
353       break;
354     case WIDEN_MULT_EXPR:
355       *code1 = MULT_EXPR;
356       break;
357     default:
358       return false;
359     }
360 
361   if (!supportable_convert_operation (NOP_EXPR, vectype_out, vectype_in,
362 				     &dummy_code))
363     return false;
364 
365   op = optab_for_tree_code (*code1, vectype_out, optab_vector);
366   return (optab_handler (op, TYPE_MODE (vectype_out)) != CODE_FOR_nothing);
367 }
368 
369 /* Function supportable_convert_operation
370 
371    Check whether an operation represented by the code CODE is a
372    convert operation that is supported by the target platform in
373    vector form (i.e., when operating on arguments of type VECTYPE_IN
374    producing a result of type VECTYPE_OUT).
375 
376    Convert operations we currently support directly are FIX_TRUNC and FLOAT.
377    This function checks if these operations are supported
378    by the target platform directly (via vector tree-codes).
379 
380    Output:
381    - CODE1 is code of vector operation to be used when
382    vectorizing the operation, if available.  */
383 
384 bool
supportable_convert_operation(enum tree_code code,tree vectype_out,tree vectype_in,enum tree_code * code1)385 supportable_convert_operation (enum tree_code code,
386 			       tree vectype_out, tree vectype_in,
387 			       enum tree_code *code1)
388 {
389   machine_mode m1,m2;
390   bool truncp;
391 
392   gcc_assert (VECTOR_TYPE_P (vectype_out) && VECTOR_TYPE_P (vectype_in));
393 
394   m1 = TYPE_MODE (vectype_out);
395   m2 = TYPE_MODE (vectype_in);
396 
397   if (!VECTOR_MODE_P (m1) || !VECTOR_MODE_P (m2))
398     return false;
399 
400   /* First check if we can done conversion directly.  */
401   if ((code == FIX_TRUNC_EXPR
402        && can_fix_p (m1,m2,TYPE_UNSIGNED (vectype_out), &truncp)
403 	  != CODE_FOR_nothing)
404       || (code == FLOAT_EXPR
405 	  && can_float_p (m1,m2,TYPE_UNSIGNED (vectype_in))
406 	     != CODE_FOR_nothing))
407     {
408       *code1 = code;
409       return true;
410     }
411 
412   if (GET_MODE_UNIT_PRECISION (m1) > GET_MODE_UNIT_PRECISION (m2)
413       && can_extend_p (m1, m2, TYPE_UNSIGNED (vectype_in)))
414     {
415       *code1 = code;
416       return true;
417     }
418 
419   if (GET_MODE_UNIT_PRECISION (m1) < GET_MODE_UNIT_PRECISION (m2)
420       && convert_optab_handler (trunc_optab, m1, m2) != CODE_FOR_nothing)
421     {
422       *code1 = code;
423       return true;
424     }
425 
426   return false;
427 }
428 
429 /* Return true iff vec_cmp_optab/vec_cmpu_optab can handle a vector comparison
430    for code CODE, comparing operands of type VALUE_TYPE and producing a result
431    of type MASK_TYPE.  */
432 
433 static bool
vec_cmp_icode_p(tree value_type,tree mask_type,enum tree_code code)434 vec_cmp_icode_p (tree value_type, tree mask_type, enum tree_code code)
435 {
436   enum rtx_code rcode = get_rtx_code_1 (code, TYPE_UNSIGNED (value_type));
437   if (rcode == UNKNOWN)
438     return false;
439 
440   return can_vec_cmp_compare_p (rcode, TYPE_MODE (value_type),
441 				TYPE_MODE (mask_type));
442 }
443 
444 /* Return true iff vec_cmpeq_optab can handle a vector comparison for code
445    CODE, comparing operands of type VALUE_TYPE and producing a result of type
446    MASK_TYPE.  */
447 
448 static bool
vec_cmp_eq_icode_p(tree value_type,tree mask_type,enum tree_code code)449 vec_cmp_eq_icode_p (tree value_type, tree mask_type, enum tree_code code)
450 {
451   if (code != EQ_EXPR && code != NE_EXPR)
452     return false;
453 
454   return get_vec_cmp_eq_icode (TYPE_MODE (value_type), TYPE_MODE (mask_type))
455 	 != CODE_FOR_nothing;
456 }
457 
458 /* Return TRUE if appropriate vector insn is available
459    for vector comparison expr with vector type VALUE_TYPE
460    and resulting mask with MASK_TYPE.  */
461 
462 bool
expand_vec_cmp_expr_p(tree value_type,tree mask_type,enum tree_code code)463 expand_vec_cmp_expr_p (tree value_type, tree mask_type, enum tree_code code)
464 {
465   return vec_cmp_icode_p (value_type, mask_type, code)
466 	 || vec_cmp_eq_icode_p (value_type, mask_type, code);
467 }
468 
469 /* Return true iff vcond_optab/vcondu_optab can handle a vector
470    comparison for code CODE, comparing operands of type CMP_OP_TYPE and
471    producing a result of type VALUE_TYPE.  */
472 
473 static bool
vcond_icode_p(tree value_type,tree cmp_op_type,enum tree_code code)474 vcond_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
475 {
476   enum rtx_code rcode = get_rtx_code_1 (code, TYPE_UNSIGNED (cmp_op_type));
477   if (rcode == UNKNOWN)
478     return false;
479 
480   return can_vcond_compare_p (rcode, TYPE_MODE (value_type),
481 			      TYPE_MODE (cmp_op_type));
482 }
483 
484 /* Return true iff vcondeq_optab can handle a vector comparison for code CODE,
485    comparing operands of type CMP_OP_TYPE and producing a result of type
486    VALUE_TYPE.  */
487 
488 static bool
vcond_eq_icode_p(tree value_type,tree cmp_op_type,enum tree_code code)489 vcond_eq_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
490 {
491   if (code != EQ_EXPR && code != NE_EXPR)
492     return false;
493 
494   return get_vcond_eq_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type))
495 	 != CODE_FOR_nothing;
496 }
497 
498 /* Return TRUE iff, appropriate vector insns are available
499    for vector cond expr with vector type VALUE_TYPE and a comparison
500    with operand vector types in CMP_OP_TYPE.  */
501 
502 bool
expand_vec_cond_expr_p(tree value_type,tree cmp_op_type,enum tree_code code)503 expand_vec_cond_expr_p (tree value_type, tree cmp_op_type, enum tree_code code)
504 {
505   machine_mode value_mode = TYPE_MODE (value_type);
506   machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
507   if (VECTOR_BOOLEAN_TYPE_P (cmp_op_type)
508       && get_vcond_mask_icode (TYPE_MODE (value_type),
509 			       TYPE_MODE (cmp_op_type)) != CODE_FOR_nothing)
510     return true;
511 
512   if (maybe_ne (GET_MODE_NUNITS (value_mode), GET_MODE_NUNITS (cmp_op_mode)))
513     return false;
514 
515   if (TREE_CODE_CLASS (code) != tcc_comparison)
516     /* This may happen, for example, if code == SSA_NAME, in which case we
517        cannot be certain whether a vector insn is available.  */
518     return false;
519 
520   return vcond_icode_p (value_type, cmp_op_type, code)
521 	 || vcond_eq_icode_p (value_type, cmp_op_type, code);
522 }
523 
524 /* Use the current target and options to initialize
525    TREE_OPTIMIZATION_OPTABS (OPTNODE).  */
526 
527 void
init_tree_optimization_optabs(tree optnode)528 init_tree_optimization_optabs (tree optnode)
529 {
530   /* Quick exit if we have already computed optabs for this target.  */
531   if (TREE_OPTIMIZATION_BASE_OPTABS (optnode) == this_target_optabs)
532     return;
533 
534   /* Forget any previous information and set up for the current target.  */
535   TREE_OPTIMIZATION_BASE_OPTABS (optnode) = this_target_optabs;
536   struct target_optabs *tmp_optabs = (struct target_optabs *)
537     TREE_OPTIMIZATION_OPTABS (optnode);
538   if (tmp_optabs)
539     memset (tmp_optabs, 0, sizeof (struct target_optabs));
540   else
541     tmp_optabs = ggc_cleared_alloc<target_optabs> ();
542 
543   /* Generate a new set of optabs into tmp_optabs.  */
544   init_all_optabs (tmp_optabs);
545 
546   /* If the optabs changed, record it.  */
547   if (memcmp (tmp_optabs, this_target_optabs, sizeof (struct target_optabs)))
548     TREE_OPTIMIZATION_OPTABS (optnode) = tmp_optabs;
549   else
550     {
551       TREE_OPTIMIZATION_OPTABS (optnode) = NULL;
552       ggc_free (tmp_optabs);
553     }
554 }
555 
556 /* Return TRUE if the target has support for vector right shift of an
557    operand of type TYPE.  If OT_TYPE is OPTAB_DEFAULT, check for existence
558    of a shift by either a scalar or a vector.  Otherwise, check only
559    for a shift that matches OT_TYPE.  */
560 
561 bool
target_supports_op_p(tree type,enum tree_code code,enum optab_subtype ot_subtype)562 target_supports_op_p (tree type, enum tree_code code,
563 		      enum optab_subtype ot_subtype)
564 {
565   optab ot = optab_for_tree_code (code, type, ot_subtype);
566   return (ot != unknown_optab
567 	  && optab_handler (ot, TYPE_MODE (type)) != CODE_FOR_nothing);
568 }
569 
570