xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/optabs-tree.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1 /* Tree-based target query functions relating to optabs
2    Copyright (C) 1987-2020 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       return TYPE_UNSIGNED (type) ? udot_prod_optab : sdot_prod_optab;
146 
147     case SAD_EXPR:
148       return TYPE_UNSIGNED (type) ? usad_optab : ssad_optab;
149 
150     case WIDEN_MULT_PLUS_EXPR:
151       return (TYPE_UNSIGNED (type)
152 	      ? (TYPE_SATURATING (type)
153 		 ? usmadd_widen_optab : umadd_widen_optab)
154 	      : (TYPE_SATURATING (type)
155 		 ? ssmadd_widen_optab : smadd_widen_optab));
156 
157     case WIDEN_MULT_MINUS_EXPR:
158       return (TYPE_UNSIGNED (type)
159 	      ? (TYPE_SATURATING (type)
160 		 ? usmsub_widen_optab : umsub_widen_optab)
161 	      : (TYPE_SATURATING (type)
162 		 ? ssmsub_widen_optab : smsub_widen_optab));
163 
164     case VEC_WIDEN_MULT_HI_EXPR:
165       return (TYPE_UNSIGNED (type)
166 	      ? vec_widen_umult_hi_optab : vec_widen_smult_hi_optab);
167 
168     case VEC_WIDEN_MULT_LO_EXPR:
169       return (TYPE_UNSIGNED (type)
170 	      ? vec_widen_umult_lo_optab : vec_widen_smult_lo_optab);
171 
172     case VEC_WIDEN_MULT_EVEN_EXPR:
173       return (TYPE_UNSIGNED (type)
174 	      ? vec_widen_umult_even_optab : vec_widen_smult_even_optab);
175 
176     case VEC_WIDEN_MULT_ODD_EXPR:
177       return (TYPE_UNSIGNED (type)
178 	      ? vec_widen_umult_odd_optab : vec_widen_smult_odd_optab);
179 
180     case VEC_WIDEN_LSHIFT_HI_EXPR:
181       return (TYPE_UNSIGNED (type)
182 	      ? vec_widen_ushiftl_hi_optab : vec_widen_sshiftl_hi_optab);
183 
184     case VEC_WIDEN_LSHIFT_LO_EXPR:
185       return (TYPE_UNSIGNED (type)
186 	      ? vec_widen_ushiftl_lo_optab : vec_widen_sshiftl_lo_optab);
187 
188     case VEC_UNPACK_HI_EXPR:
189       return (TYPE_UNSIGNED (type)
190 	      ? vec_unpacku_hi_optab : vec_unpacks_hi_optab);
191 
192     case VEC_UNPACK_LO_EXPR:
193       return (TYPE_UNSIGNED (type)
194 	      ? vec_unpacku_lo_optab : vec_unpacks_lo_optab);
195 
196     case VEC_UNPACK_FLOAT_HI_EXPR:
197       /* The signedness is determined from input operand.  */
198       return (TYPE_UNSIGNED (type)
199 	      ? vec_unpacku_float_hi_optab : vec_unpacks_float_hi_optab);
200 
201     case VEC_UNPACK_FLOAT_LO_EXPR:
202       /* The signedness is determined from input operand.  */
203       return (TYPE_UNSIGNED (type)
204 	      ? vec_unpacku_float_lo_optab : vec_unpacks_float_lo_optab);
205 
206     case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
207       /* The signedness is determined from output operand.  */
208       return (TYPE_UNSIGNED (type)
209 	      ? vec_unpack_ufix_trunc_hi_optab
210 	      : vec_unpack_sfix_trunc_hi_optab);
211 
212     case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
213       /* The signedness is determined from output operand.  */
214       return (TYPE_UNSIGNED (type)
215 	      ? vec_unpack_ufix_trunc_lo_optab
216 	      : vec_unpack_sfix_trunc_lo_optab);
217 
218     case VEC_PACK_TRUNC_EXPR:
219       return vec_pack_trunc_optab;
220 
221     case VEC_PACK_SAT_EXPR:
222       return TYPE_UNSIGNED (type) ? vec_pack_usat_optab : vec_pack_ssat_optab;
223 
224     case VEC_PACK_FIX_TRUNC_EXPR:
225       /* The signedness is determined from output operand.  */
226       return (TYPE_UNSIGNED (type)
227 	      ? vec_pack_ufix_trunc_optab : vec_pack_sfix_trunc_optab);
228 
229     case VEC_PACK_FLOAT_EXPR:
230       /* The signedness is determined from input operand.  */
231       return (TYPE_UNSIGNED (type)
232 	      ? vec_packu_float_optab : vec_packs_float_optab);
233 
234     case VEC_DUPLICATE_EXPR:
235       return vec_duplicate_optab;
236 
237     case VEC_SERIES_EXPR:
238       return vec_series_optab;
239 
240     default:
241       break;
242     }
243 
244   trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
245   switch (code)
246     {
247     case POINTER_PLUS_EXPR:
248     case PLUS_EXPR:
249       if (TYPE_SATURATING (type))
250 	return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
251       return trapv ? addv_optab : add_optab;
252 
253     case POINTER_DIFF_EXPR:
254     case MINUS_EXPR:
255       if (TYPE_SATURATING (type))
256 	return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
257       return trapv ? subv_optab : sub_optab;
258 
259     case MULT_EXPR:
260       if (TYPE_SATURATING (type))
261 	return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
262       return trapv ? smulv_optab : smul_optab;
263 
264     case NEGATE_EXPR:
265       if (TYPE_SATURATING (type))
266 	return TYPE_UNSIGNED (type) ? usneg_optab : ssneg_optab;
267       return trapv ? negv_optab : neg_optab;
268 
269     case ABS_EXPR:
270       return trapv ? absv_optab : abs_optab;
271 
272     case ABSU_EXPR:
273       return abs_optab;
274     default:
275       return unknown_optab;
276     }
277 }
278 
279 /* Function supportable_convert_operation
280 
281    Check whether an operation represented by the code CODE is a
282    convert operation that is supported by the target platform in
283    vector form (i.e., when operating on arguments of type VECTYPE_IN
284    producing a result of type VECTYPE_OUT).
285 
286    Convert operations we currently support directly are FIX_TRUNC and FLOAT.
287    This function checks if these operations are supported
288    by the target platform directly (via vector tree-codes).
289 
290    Output:
291    - CODE1 is code of vector operation to be used when
292    vectorizing the operation, if available.  */
293 
294 bool
supportable_convert_operation(enum tree_code code,tree vectype_out,tree vectype_in,enum tree_code * code1)295 supportable_convert_operation (enum tree_code code,
296 			       tree vectype_out, tree vectype_in,
297 			       enum tree_code *code1)
298 {
299   machine_mode m1,m2;
300   bool truncp;
301 
302   gcc_assert (VECTOR_TYPE_P (vectype_out) && VECTOR_TYPE_P (vectype_in));
303 
304   m1 = TYPE_MODE (vectype_out);
305   m2 = TYPE_MODE (vectype_in);
306 
307   if (!VECTOR_MODE_P (m1) || !VECTOR_MODE_P (m2))
308     return false;
309 
310   /* First check if we can done conversion directly.  */
311   if ((code == FIX_TRUNC_EXPR
312        && can_fix_p (m1,m2,TYPE_UNSIGNED (vectype_out), &truncp)
313 	  != CODE_FOR_nothing)
314       || (code == FLOAT_EXPR
315 	  && can_float_p (m1,m2,TYPE_UNSIGNED (vectype_in))
316 	     != CODE_FOR_nothing))
317     {
318       *code1 = code;
319       return true;
320     }
321 
322   if (GET_MODE_UNIT_PRECISION (m1) > GET_MODE_UNIT_PRECISION (m2)
323       && can_extend_p (m1, m2, TYPE_UNSIGNED (vectype_in)))
324     {
325       *code1 = code;
326       return true;
327     }
328 
329   if (GET_MODE_UNIT_PRECISION (m1) < GET_MODE_UNIT_PRECISION (m2)
330       && convert_optab_handler (trunc_optab, m1, m2) != CODE_FOR_nothing)
331     {
332       *code1 = code;
333       return true;
334     }
335 
336   return false;
337 }
338 
339 /* Return TRUE if appropriate vector insn is available
340    for vector comparison expr with vector type VALUE_TYPE
341    and resulting mask with MASK_TYPE.  */
342 
343 bool
expand_vec_cmp_expr_p(tree value_type,tree mask_type,enum tree_code code)344 expand_vec_cmp_expr_p (tree value_type, tree mask_type, enum tree_code code)
345 {
346   if (get_vec_cmp_icode (TYPE_MODE (value_type), TYPE_MODE (mask_type),
347 			 TYPE_UNSIGNED (value_type)) != CODE_FOR_nothing)
348     return true;
349   if ((code == EQ_EXPR || code == NE_EXPR)
350       && (get_vec_cmp_eq_icode (TYPE_MODE (value_type), TYPE_MODE (mask_type))
351 	  != CODE_FOR_nothing))
352     return true;
353   return false;
354 }
355 
356 /* Return true iff vcond_optab/vcondu_optab can handle a vector
357    comparison for code CODE, comparing operands of type CMP_OP_TYPE and
358    producing a result of type VALUE_TYPE.  */
359 
360 static bool
vcond_icode_p(tree value_type,tree cmp_op_type,enum tree_code code)361 vcond_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
362 {
363   return can_vcond_compare_p (get_rtx_code (code, TYPE_UNSIGNED (cmp_op_type)),
364 			      TYPE_MODE (value_type), TYPE_MODE (cmp_op_type));
365 }
366 
367 /* Return true iff vcondeq_optab can handle a vector comparison for code CODE,
368    comparing operands of type CMP_OP_TYPE and producing a result of type
369    VALUE_TYPE.  */
370 
371 static bool
vcond_eq_icode_p(tree value_type,tree cmp_op_type,enum tree_code code)372 vcond_eq_icode_p (tree value_type, tree cmp_op_type, enum tree_code code)
373 {
374   if (code != EQ_EXPR && code != NE_EXPR)
375     return false;
376 
377   return get_vcond_eq_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type))
378 	 != CODE_FOR_nothing;
379 }
380 
381 /* Return TRUE iff, appropriate vector insns are available
382    for vector cond expr with vector type VALUE_TYPE and a comparison
383    with operand vector types in CMP_OP_TYPE.  */
384 
385 bool
expand_vec_cond_expr_p(tree value_type,tree cmp_op_type,enum tree_code code)386 expand_vec_cond_expr_p (tree value_type, tree cmp_op_type, enum tree_code code)
387 {
388   machine_mode value_mode = TYPE_MODE (value_type);
389   machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type);
390   if (VECTOR_BOOLEAN_TYPE_P (cmp_op_type)
391       && get_vcond_mask_icode (TYPE_MODE (value_type),
392 			       TYPE_MODE (cmp_op_type)) != CODE_FOR_nothing)
393     return true;
394 
395   if (maybe_ne (GET_MODE_SIZE (value_mode), GET_MODE_SIZE (cmp_op_mode))
396       || maybe_ne (GET_MODE_NUNITS (value_mode), GET_MODE_NUNITS (cmp_op_mode)))
397     return false;
398 
399   if (TREE_CODE_CLASS (code) != tcc_comparison)
400     /* This may happen, for example, if code == SSA_NAME, in which case we
401        cannot be certain whether a vector insn is available.  */
402     return false;
403 
404   return vcond_icode_p (value_type, cmp_op_type, code)
405 	 || vcond_eq_icode_p (value_type, cmp_op_type, code);
406 }
407 
408 /* Use the current target and options to initialize
409    TREE_OPTIMIZATION_OPTABS (OPTNODE).  */
410 
411 void
init_tree_optimization_optabs(tree optnode)412 init_tree_optimization_optabs (tree optnode)
413 {
414   /* Quick exit if we have already computed optabs for this target.  */
415   if (TREE_OPTIMIZATION_BASE_OPTABS (optnode) == this_target_optabs)
416     return;
417 
418   /* Forget any previous information and set up for the current target.  */
419   TREE_OPTIMIZATION_BASE_OPTABS (optnode) = this_target_optabs;
420   struct target_optabs *tmp_optabs = (struct target_optabs *)
421     TREE_OPTIMIZATION_OPTABS (optnode);
422   if (tmp_optabs)
423     memset (tmp_optabs, 0, sizeof (struct target_optabs));
424   else
425     tmp_optabs = ggc_cleared_alloc<target_optabs> ();
426 
427   /* Generate a new set of optabs into tmp_optabs.  */
428   init_all_optabs (tmp_optabs);
429 
430   /* If the optabs changed, record it.  */
431   if (memcmp (tmp_optabs, this_target_optabs, sizeof (struct target_optabs)))
432     TREE_OPTIMIZATION_OPTABS (optnode) = tmp_optabs;
433   else
434     {
435       TREE_OPTIMIZATION_OPTABS (optnode) = NULL;
436       ggc_free (tmp_optabs);
437     }
438 }
439 
440 /* Return TRUE if the target has support for vector right shift of an
441    operand of type TYPE.  If OT_TYPE is OPTAB_DEFAULT, check for existence
442    of a shift by either a scalar or a vector.  Otherwise, check only
443    for a shift that matches OT_TYPE.  */
444 
445 bool
target_supports_op_p(tree type,enum tree_code code,enum optab_subtype ot_subtype)446 target_supports_op_p (tree type, enum tree_code code,
447 		      enum optab_subtype ot_subtype)
448 {
449   optab ot = optab_for_tree_code (code, type, ot_subtype);
450   return (ot != unknown_optab
451 	  && optab_handler (ot, TYPE_MODE (type)) != CODE_FOR_nothing);
452 }
453 
454