1/* Tree-based target query functions relating to optabs
2   Copyright (C) 1987-2020 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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.  */
37optab
38optab_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
294bool
295supportable_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
343bool
344expand_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
360static bool
361vcond_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
371static bool
372vcond_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
385bool
386expand_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
411void
412init_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
445bool
446target_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