]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/omp-simd-clone.cc
Don't build readline/libreadline.a, when --with-system-readline is supplied
[thirdparty/gcc.git] / gcc / omp-simd-clone.cc
1 /* OMP constructs' SIMD clone supporting code.
2
3 Copyright (C) 2005-2022 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "cfghooks.h"
29 #include "alloc-pool.h"
30 #include "tree-pass.h"
31 #include "ssa.h"
32 #include "cgraph.h"
33 #include "pretty-print.h"
34 #include "diagnostic-core.h"
35 #include "fold-const.h"
36 #include "stor-layout.h"
37 #include "cfganal.h"
38 #include "gimplify.h"
39 #include "gimple-iterator.h"
40 #include "gimplify-me.h"
41 #include "gimple-walk.h"
42 #include "langhooks.h"
43 #include "tree-cfg.h"
44 #include "tree-into-ssa.h"
45 #include "tree-dfa.h"
46 #include "cfgloop.h"
47 #include "symbol-summary.h"
48 #include "ipa-param-manipulation.h"
49 #include "tree-eh.h"
50 #include "varasm.h"
51 #include "stringpool.h"
52 #include "attribs.h"
53 #include "omp-simd-clone.h"
54
55 /* Return the number of elements in vector type VECTYPE, which is associated
56 with a SIMD clone. At present these always have a constant length. */
57
58 static unsigned HOST_WIDE_INT
59 simd_clone_subparts (tree vectype)
60 {
61 return TYPE_VECTOR_SUBPARTS (vectype).to_constant ();
62 }
63
64 /* Allocate a fresh `simd_clone' and return it. NARGS is the number
65 of arguments to reserve space for. */
66
67 static struct cgraph_simd_clone *
68 simd_clone_struct_alloc (int nargs)
69 {
70 struct cgraph_simd_clone *clone_info;
71 size_t len = (sizeof (struct cgraph_simd_clone)
72 + nargs * sizeof (struct cgraph_simd_clone_arg));
73 clone_info = (struct cgraph_simd_clone *)
74 ggc_internal_cleared_alloc (len);
75 return clone_info;
76 }
77
78 /* Make a copy of the `struct cgraph_simd_clone' in FROM to TO. */
79
80 static inline void
81 simd_clone_struct_copy (struct cgraph_simd_clone *to,
82 struct cgraph_simd_clone *from)
83 {
84 memcpy (to, from, (sizeof (struct cgraph_simd_clone)
85 + ((from->nargs - from->inbranch)
86 * sizeof (struct cgraph_simd_clone_arg))));
87 }
88
89 /* Fill an empty vector ARGS with parameter types of function FNDECL. This
90 uses TYPE_ARG_TYPES if available, otherwise falls back to types of
91 DECL_ARGUMENTS types. */
92
93 static void
94 simd_clone_vector_of_formal_parm_types (vec<tree> *args, tree fndecl)
95 {
96 if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
97 {
98 push_function_arg_types (args, TREE_TYPE (fndecl));
99 return;
100 }
101 push_function_arg_decls (args, fndecl);
102 unsigned int i;
103 tree arg;
104 FOR_EACH_VEC_ELT (*args, i, arg)
105 (*args)[i] = TREE_TYPE ((*args)[i]);
106 }
107
108 /* Given a simd function in NODE, extract the simd specific
109 information from the OMP clauses passed in CLAUSES, and return
110 the struct cgraph_simd_clone * if it should be cloned. *INBRANCH_SPECIFIED
111 is set to TRUE if the `inbranch' or `notinbranch' clause specified,
112 otherwise set to FALSE. */
113
114 static struct cgraph_simd_clone *
115 simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
116 bool *inbranch_specified)
117 {
118 auto_vec<tree> args;
119 simd_clone_vector_of_formal_parm_types (&args, node->decl);
120 tree t;
121 int n;
122 *inbranch_specified = false;
123
124 n = args.length ();
125 if (n > 0 && args.last () == void_type_node)
126 n--;
127
128 /* Allocate one more than needed just in case this is an in-branch
129 clone which will require a mask argument. */
130 struct cgraph_simd_clone *clone_info = simd_clone_struct_alloc (n + 1);
131 clone_info->nargs = n;
132
133 if (!clauses)
134 goto out;
135
136 clauses = TREE_VALUE (clauses);
137 if (!clauses || TREE_CODE (clauses) != OMP_CLAUSE)
138 goto out;
139
140 for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t))
141 {
142 switch (OMP_CLAUSE_CODE (t))
143 {
144 case OMP_CLAUSE_INBRANCH:
145 clone_info->inbranch = 1;
146 *inbranch_specified = true;
147 break;
148 case OMP_CLAUSE_NOTINBRANCH:
149 clone_info->inbranch = 0;
150 *inbranch_specified = true;
151 break;
152 case OMP_CLAUSE_SIMDLEN:
153 clone_info->simdlen
154 = TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
155 break;
156 case OMP_CLAUSE_LINEAR:
157 {
158 tree decl = OMP_CLAUSE_DECL (t);
159 tree step = OMP_CLAUSE_LINEAR_STEP (t);
160 int argno = TREE_INT_CST_LOW (decl);
161 if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (t))
162 {
163 enum cgraph_simd_clone_arg_type arg_type;
164 if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
165 switch (OMP_CLAUSE_LINEAR_KIND (t))
166 {
167 case OMP_CLAUSE_LINEAR_REF:
168 arg_type
169 = SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP;
170 break;
171 case OMP_CLAUSE_LINEAR_UVAL:
172 arg_type
173 = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP;
174 break;
175 case OMP_CLAUSE_LINEAR_VAL:
176 case OMP_CLAUSE_LINEAR_DEFAULT:
177 arg_type
178 = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP;
179 break;
180 default:
181 gcc_unreachable ();
182 }
183 else
184 arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP;
185 clone_info->args[argno].arg_type = arg_type;
186 clone_info->args[argno].linear_step = tree_to_shwi (step);
187 gcc_assert (clone_info->args[argno].linear_step >= 0
188 && clone_info->args[argno].linear_step < n);
189 }
190 else
191 {
192 if (POINTER_TYPE_P (args[argno]))
193 step = fold_convert (ssizetype, step);
194 if (!tree_fits_shwi_p (step))
195 {
196 warning_at (OMP_CLAUSE_LOCATION (t), 0,
197 "ignoring large linear step");
198 return NULL;
199 }
200 else if (integer_zerop (step))
201 {
202 warning_at (OMP_CLAUSE_LOCATION (t), 0,
203 "ignoring zero linear step");
204 return NULL;
205 }
206 else
207 {
208 enum cgraph_simd_clone_arg_type arg_type;
209 if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
210 switch (OMP_CLAUSE_LINEAR_KIND (t))
211 {
212 case OMP_CLAUSE_LINEAR_REF:
213 arg_type
214 = SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP;
215 break;
216 case OMP_CLAUSE_LINEAR_UVAL:
217 arg_type
218 = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP;
219 break;
220 case OMP_CLAUSE_LINEAR_VAL:
221 case OMP_CLAUSE_LINEAR_DEFAULT:
222 arg_type
223 = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP;
224 break;
225 default:
226 gcc_unreachable ();
227 }
228 else
229 arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP;
230 clone_info->args[argno].arg_type = arg_type;
231 clone_info->args[argno].linear_step = tree_to_shwi (step);
232 }
233 }
234 break;
235 }
236 case OMP_CLAUSE_UNIFORM:
237 {
238 tree decl = OMP_CLAUSE_DECL (t);
239 int argno = tree_to_uhwi (decl);
240 clone_info->args[argno].arg_type
241 = SIMD_CLONE_ARG_TYPE_UNIFORM;
242 break;
243 }
244 case OMP_CLAUSE_ALIGNED:
245 {
246 /* Ignore aligned (x) for declare simd, for the ABI we really
247 need an alignment specified. */
248 if (OMP_CLAUSE_ALIGNED_ALIGNMENT (t) == NULL_TREE)
249 break;
250 tree decl = OMP_CLAUSE_DECL (t);
251 int argno = tree_to_uhwi (decl);
252 clone_info->args[argno].alignment
253 = TREE_INT_CST_LOW (OMP_CLAUSE_ALIGNED_ALIGNMENT (t));
254 break;
255 }
256 default:
257 break;
258 }
259 }
260
261 out:
262 if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (node->decl))))
263 {
264 warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
265 "ignoring %<#pragma omp declare simd%> on function "
266 "with %<_Atomic%> qualified return type");
267 return NULL;
268 }
269
270 for (unsigned int argno = 0; argno < clone_info->nargs; argno++)
271 if (TYPE_ATOMIC (args[argno])
272 && clone_info->args[argno].arg_type != SIMD_CLONE_ARG_TYPE_UNIFORM)
273 {
274 warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
275 "ignoring %<#pragma omp declare simd%> on function "
276 "with %<_Atomic%> qualified non-%<uniform%> argument");
277 args.release ();
278 return NULL;
279 }
280
281 return clone_info;
282 }
283
284 /* Given a SIMD clone in NODE, calculate the characteristic data
285 type and return the coresponding type. The characteristic data
286 type is computed as described in the Intel Vector ABI. */
287
288 static tree
289 simd_clone_compute_base_data_type (struct cgraph_node *node,
290 struct cgraph_simd_clone *clone_info)
291 {
292 tree type = integer_type_node;
293 tree fndecl = node->decl;
294
295 /* a) For non-void function, the characteristic data type is the
296 return type. */
297 if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE)
298 type = TREE_TYPE (TREE_TYPE (fndecl));
299
300 /* b) If the function has any non-uniform, non-linear parameters,
301 then the characteristic data type is the type of the first
302 such parameter. */
303 else
304 {
305 auto_vec<tree> map;
306 simd_clone_vector_of_formal_parm_types (&map, fndecl);
307 for (unsigned int i = 0; i < clone_info->nargs; ++i)
308 if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
309 {
310 type = map[i];
311 break;
312 }
313 }
314
315 /* c) If the characteristic data type determined by a) or b) above
316 is struct, union, or class type which is pass-by-value (except
317 for the type that maps to the built-in complex data type), the
318 characteristic data type is int. */
319 if (RECORD_OR_UNION_TYPE_P (type)
320 && !aggregate_value_p (type, NULL)
321 && TREE_CODE (type) != COMPLEX_TYPE)
322 return integer_type_node;
323
324 /* d) If none of the above three classes is applicable, the
325 characteristic data type is int. */
326
327 return type;
328
329 /* e) For Intel Xeon Phi native and offload compilation, if the
330 resulting characteristic data type is 8-bit or 16-bit integer
331 data type, the characteristic data type is int. */
332 /* Well, we don't handle Xeon Phi yet. */
333 }
334
335 static tree
336 simd_clone_mangle (struct cgraph_node *node,
337 struct cgraph_simd_clone *clone_info)
338 {
339 char vecsize_mangle = clone_info->vecsize_mangle;
340 char mask = clone_info->inbranch ? 'M' : 'N';
341 poly_uint64 simdlen = clone_info->simdlen;
342 unsigned int n;
343 pretty_printer pp;
344
345 gcc_assert (vecsize_mangle && maybe_ne (simdlen, 0U));
346
347 pp_string (&pp, "_ZGV");
348 pp_character (&pp, vecsize_mangle);
349 pp_character (&pp, mask);
350 /* For now, simdlen is always constant, while variable simdlen pp 'n'. */
351 unsigned int len = simdlen.to_constant ();
352 pp_decimal_int (&pp, (len));
353
354 for (n = 0; n < clone_info->nargs; ++n)
355 {
356 struct cgraph_simd_clone_arg arg = clone_info->args[n];
357
358 switch (arg.arg_type)
359 {
360 case SIMD_CLONE_ARG_TYPE_UNIFORM:
361 pp_character (&pp, 'u');
362 break;
363 case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
364 pp_character (&pp, 'l');
365 goto mangle_linear;
366 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
367 pp_character (&pp, 'R');
368 goto mangle_linear;
369 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
370 pp_character (&pp, 'L');
371 goto mangle_linear;
372 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
373 pp_character (&pp, 'U');
374 goto mangle_linear;
375 mangle_linear:
376 gcc_assert (arg.linear_step != 0);
377 if (arg.linear_step > 1)
378 pp_unsigned_wide_integer (&pp, arg.linear_step);
379 else if (arg.linear_step < 0)
380 {
381 pp_character (&pp, 'n');
382 pp_unsigned_wide_integer (&pp, (-(unsigned HOST_WIDE_INT)
383 arg.linear_step));
384 }
385 break;
386 case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
387 pp_string (&pp, "ls");
388 pp_unsigned_wide_integer (&pp, arg.linear_step);
389 break;
390 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
391 pp_string (&pp, "Rs");
392 pp_unsigned_wide_integer (&pp, arg.linear_step);
393 break;
394 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
395 pp_string (&pp, "Ls");
396 pp_unsigned_wide_integer (&pp, arg.linear_step);
397 break;
398 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
399 pp_string (&pp, "Us");
400 pp_unsigned_wide_integer (&pp, arg.linear_step);
401 break;
402 default:
403 pp_character (&pp, 'v');
404 }
405 if (arg.alignment)
406 {
407 pp_character (&pp, 'a');
408 pp_decimal_int (&pp, arg.alignment);
409 }
410 }
411
412 pp_underscore (&pp);
413 const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
414 if (*str == '*')
415 ++str;
416 pp_string (&pp, str);
417 str = pp_formatted_text (&pp);
418
419 /* If there already is a SIMD clone with the same mangled name, don't
420 add another one. This can happen e.g. for
421 #pragma omp declare simd
422 #pragma omp declare simd simdlen(8)
423 int foo (int, int);
424 if the simdlen is assumed to be 8 for the first one, etc. */
425 for (struct cgraph_node *clone = node->simd_clones; clone;
426 clone = clone->simdclone->next_clone)
427 if (id_equal (DECL_ASSEMBLER_NAME (clone->decl), str))
428 return NULL_TREE;
429
430 return get_identifier (str);
431 }
432
433 /* Create a simd clone of OLD_NODE and return it. */
434
435 static struct cgraph_node *
436 simd_clone_create (struct cgraph_node *old_node)
437 {
438 struct cgraph_node *new_node;
439 if (old_node->definition)
440 {
441 if (!old_node->has_gimple_body_p ())
442 return NULL;
443 old_node->get_body ();
444 new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL,
445 NULL, NULL,
446 "simdclone");
447 }
448 else
449 {
450 tree old_decl = old_node->decl;
451 tree new_decl = copy_node (old_node->decl);
452 DECL_NAME (new_decl) = clone_function_name_numbered (old_decl,
453 "simdclone");
454 SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
455 SET_DECL_RTL (new_decl, NULL);
456 DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
457 DECL_STATIC_DESTRUCTOR (new_decl) = 0;
458 new_node = old_node->create_version_clone (new_decl, vNULL, NULL);
459 if (old_node->in_other_partition)
460 new_node->in_other_partition = 1;
461 }
462 if (new_node == NULL)
463 return new_node;
464
465 set_decl_built_in_function (new_node->decl, NOT_BUILT_IN, 0);
466 TREE_PUBLIC (new_node->decl) = TREE_PUBLIC (old_node->decl);
467 DECL_COMDAT (new_node->decl) = DECL_COMDAT (old_node->decl);
468 DECL_WEAK (new_node->decl) = DECL_WEAK (old_node->decl);
469 DECL_EXTERNAL (new_node->decl) = DECL_EXTERNAL (old_node->decl);
470 DECL_VISIBILITY_SPECIFIED (new_node->decl)
471 = DECL_VISIBILITY_SPECIFIED (old_node->decl);
472 DECL_VISIBILITY (new_node->decl) = DECL_VISIBILITY (old_node->decl);
473 DECL_DLLIMPORT_P (new_node->decl) = DECL_DLLIMPORT_P (old_node->decl);
474 if (DECL_ONE_ONLY (old_node->decl))
475 make_decl_one_only (new_node->decl, DECL_ASSEMBLER_NAME (new_node->decl));
476
477 /* The method cgraph_version_clone_with_body () will force the new
478 symbol local. Undo this, and inherit external visibility from
479 the old node. */
480 new_node->local = old_node->local;
481 new_node->externally_visible = old_node->externally_visible;
482 new_node->calls_declare_variant_alt = old_node->calls_declare_variant_alt;
483
484 return new_node;
485 }
486
487 /* Adjust the return type of the given function to its appropriate
488 vector counterpart. Returns a simd array to be used throughout the
489 function as a return value. */
490
491 static tree
492 simd_clone_adjust_return_type (struct cgraph_node *node)
493 {
494 tree fndecl = node->decl;
495 tree orig_rettype = TREE_TYPE (TREE_TYPE (fndecl));
496 poly_uint64 veclen;
497 tree t;
498
499 /* Adjust the function return type. */
500 if (orig_rettype == void_type_node)
501 return NULL_TREE;
502 t = TREE_TYPE (TREE_TYPE (fndecl));
503 if (INTEGRAL_TYPE_P (t) || POINTER_TYPE_P (t))
504 veclen = node->simdclone->vecsize_int;
505 else
506 veclen = node->simdclone->vecsize_float;
507 if (known_eq (veclen, 0U))
508 veclen = node->simdclone->simdlen;
509 else
510 veclen = exact_div (veclen, GET_MODE_BITSIZE (SCALAR_TYPE_MODE (t)));
511 if (multiple_p (veclen, node->simdclone->simdlen))
512 veclen = node->simdclone->simdlen;
513 if (POINTER_TYPE_P (t))
514 t = pointer_sized_int_node;
515 if (known_eq (veclen, node->simdclone->simdlen))
516 t = build_vector_type (t, node->simdclone->simdlen);
517 else
518 {
519 t = build_vector_type (t, veclen);
520 t = build_array_type_nelts (t, exact_div (node->simdclone->simdlen,
521 veclen));
522 }
523 TREE_TYPE (TREE_TYPE (fndecl)) = t;
524 if (!node->definition)
525 return NULL_TREE;
526
527 t = DECL_RESULT (fndecl);
528 /* Adjust the DECL_RESULT. */
529 gcc_assert (TREE_TYPE (t) != void_type_node);
530 TREE_TYPE (t) = TREE_TYPE (TREE_TYPE (fndecl));
531 relayout_decl (t);
532
533 tree atype = build_array_type_nelts (orig_rettype,
534 node->simdclone->simdlen);
535 if (maybe_ne (veclen, node->simdclone->simdlen))
536 return build1 (VIEW_CONVERT_EXPR, atype, t);
537
538 /* Set up a SIMD array to use as the return value. */
539 tree retval = create_tmp_var_raw (atype, "retval");
540 gimple_add_tmp_var (retval);
541 return retval;
542 }
543
544 /* Each vector argument has a corresponding array to be used locally
545 as part of the eventual loop. Create such temporary array and
546 return it.
547
548 PREFIX is the prefix to be used for the temporary.
549
550 TYPE is the inner element type.
551
552 SIMDLEN is the number of elements. */
553
554 static tree
555 create_tmp_simd_array (const char *prefix, tree type, poly_uint64 simdlen)
556 {
557 tree atype = build_array_type_nelts (type, simdlen);
558 tree avar = create_tmp_var_raw (atype, prefix);
559 gimple_add_tmp_var (avar);
560 return avar;
561 }
562
563 /* Modify the function argument types to their corresponding vector
564 counterparts if appropriate. Also, create one array for each simd
565 argument to be used locally when using the function arguments as
566 part of the loop.
567
568 NODE is the function whose arguments are to be adjusted.
569
570 If NODE does not represent function definition, returns NULL. Otherwise
571 returns an adjustment class that will be filled describing how the argument
572 declarations will be remapped. New arguments which are not to be remapped
573 are marked with USER_FLAG. */
574
575 static ipa_param_body_adjustments *
576 simd_clone_adjust_argument_types (struct cgraph_node *node)
577 {
578 auto_vec<tree> args;
579
580 if (node->definition)
581 push_function_arg_decls (&args, node->decl);
582 else
583 simd_clone_vector_of_formal_parm_types (&args, node->decl);
584 struct cgraph_simd_clone *sc = node->simdclone;
585 vec<ipa_adjusted_param, va_gc> *new_params = NULL;
586 vec_safe_reserve (new_params, sc->nargs);
587 unsigned i, j, k;
588 poly_uint64 veclen;
589
590 for (i = 0; i < sc->nargs; ++i)
591 {
592 ipa_adjusted_param adj;
593 memset (&adj, 0, sizeof (adj));
594 tree parm = args[i];
595 tree parm_type = node->definition ? TREE_TYPE (parm) : parm;
596 adj.base_index = i;
597 adj.prev_clone_index = i;
598
599 sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
600 sc->args[i].orig_type = parm_type;
601
602 switch (sc->args[i].arg_type)
603 {
604 default:
605 /* No adjustment necessary for scalar arguments. */
606 adj.op = IPA_PARAM_OP_COPY;
607 break;
608 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
609 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
610 if (node->definition)
611 sc->args[i].simd_array
612 = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
613 TREE_TYPE (parm_type),
614 sc->simdlen);
615 adj.op = IPA_PARAM_OP_COPY;
616 break;
617 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
618 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
619 case SIMD_CLONE_ARG_TYPE_VECTOR:
620 if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type))
621 veclen = sc->vecsize_int;
622 else
623 veclen = sc->vecsize_float;
624 if (known_eq (veclen, 0U))
625 veclen = sc->simdlen;
626 else
627 veclen
628 = exact_div (veclen,
629 GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type)));
630 if (multiple_p (veclen, sc->simdlen))
631 veclen = sc->simdlen;
632 adj.op = IPA_PARAM_OP_NEW;
633 adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
634 if (POINTER_TYPE_P (parm_type))
635 adj.type = build_vector_type (pointer_sized_int_node, veclen);
636 else
637 adj.type = build_vector_type (parm_type, veclen);
638 sc->args[i].vector_type = adj.type;
639 k = vector_unroll_factor (sc->simdlen, veclen);
640 for (j = 1; j < k; j++)
641 {
642 vec_safe_push (new_params, adj);
643 if (j == 1)
644 {
645 memset (&adj, 0, sizeof (adj));
646 adj.op = IPA_PARAM_OP_NEW;
647 adj.user_flag = 1;
648 adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
649 adj.base_index = i;
650 adj.prev_clone_index = i;
651 adj.type = sc->args[i].vector_type;
652 }
653 }
654
655 if (node->definition)
656 sc->args[i].simd_array
657 = create_tmp_simd_array (DECL_NAME (parm)
658 ? IDENTIFIER_POINTER (DECL_NAME (parm))
659 : NULL, parm_type, sc->simdlen);
660 }
661 vec_safe_push (new_params, adj);
662 }
663
664 if (sc->inbranch)
665 {
666 tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
667 ipa_adjusted_param adj;
668 memset (&adj, 0, sizeof (adj));
669 adj.op = IPA_PARAM_OP_NEW;
670 adj.user_flag = 1;
671 adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
672
673 adj.base_index = i;
674 adj.prev_clone_index = i;
675 if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
676 veclen = sc->vecsize_int;
677 else
678 veclen = sc->vecsize_float;
679 if (known_eq (veclen, 0U))
680 veclen = sc->simdlen;
681 else
682 veclen = exact_div (veclen,
683 GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type)));
684 if (multiple_p (veclen, sc->simdlen))
685 veclen = sc->simdlen;
686 if (sc->mask_mode != VOIDmode)
687 adj.type
688 = lang_hooks.types.type_for_mode (sc->mask_mode, 1);
689 else if (POINTER_TYPE_P (base_type))
690 adj.type = build_vector_type (pointer_sized_int_node, veclen);
691 else
692 adj.type = build_vector_type (base_type, veclen);
693 vec_safe_push (new_params, adj);
694
695 k = vector_unroll_factor (sc->simdlen, veclen);
696 for (j = 1; j < k; j++)
697 vec_safe_push (new_params, adj);
698
699 /* We have previously allocated one extra entry for the mask. Use
700 it and fill it. */
701 sc->nargs++;
702 if (sc->mask_mode != VOIDmode)
703 base_type = boolean_type_node;
704 if (node->definition)
705 {
706 sc->args[i].orig_arg
707 = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type);
708 if (sc->mask_mode == VOIDmode)
709 sc->args[i].simd_array
710 = create_tmp_simd_array ("mask", base_type, sc->simdlen);
711 else if (k > 1)
712 sc->args[i].simd_array
713 = create_tmp_simd_array ("mask", adj.type, k);
714 else
715 sc->args[i].simd_array = NULL_TREE;
716 }
717 sc->args[i].orig_type = base_type;
718 sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK;
719 }
720
721 if (node->definition)
722 {
723 ipa_param_body_adjustments *adjustments
724 = new ipa_param_body_adjustments (new_params, node->decl);
725
726 adjustments->modify_formal_parameters ();
727 return adjustments;
728 }
729 else
730 {
731 tree new_arg_types = NULL_TREE, new_reversed;
732 bool last_parm_void = false;
733 if (args.length () > 0 && args.last () == void_type_node)
734 last_parm_void = true;
735
736 gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
737 j = vec_safe_length (new_params);
738 for (i = 0; i < j; i++)
739 {
740 struct ipa_adjusted_param *adj = &(*new_params)[i];
741 tree ptype;
742 if (adj->op == IPA_PARAM_OP_COPY)
743 ptype = args[adj->base_index];
744 else
745 ptype = adj->type;
746 new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types);
747 }
748 new_reversed = nreverse (new_arg_types);
749 if (last_parm_void)
750 {
751 if (new_reversed)
752 TREE_CHAIN (new_arg_types) = void_list_node;
753 else
754 new_reversed = void_list_node;
755 }
756 TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed;
757 return NULL;
758 }
759 }
760
761 /* Initialize and copy the function arguments in NODE to their
762 corresponding local simd arrays. Returns a fresh gimple_seq with
763 the instruction sequence generated. */
764
765 static gimple_seq
766 simd_clone_init_simd_arrays (struct cgraph_node *node,
767 ipa_param_body_adjustments *adjustments)
768 {
769 gimple_seq seq = NULL;
770 unsigned i = 0, j = 0, k;
771
772 for (tree arg = DECL_ARGUMENTS (node->decl);
773 arg;
774 arg = DECL_CHAIN (arg), i++, j++)
775 {
776 if ((*adjustments->m_adj_params)[j].op == IPA_PARAM_OP_COPY
777 || POINTER_TYPE_P (TREE_TYPE (arg)))
778 continue;
779
780 node->simdclone->args[i].vector_arg = arg;
781
782 tree array = node->simdclone->args[i].simd_array;
783 if (node->simdclone->mask_mode != VOIDmode
784 && node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
785 {
786 if (array == NULL_TREE)
787 continue;
788 unsigned int l
789 = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array))));
790 for (k = 0; k <= l; k++)
791 {
792 if (k)
793 {
794 arg = DECL_CHAIN (arg);
795 j++;
796 }
797 tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
798 array, size_int (k), NULL, NULL);
799 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
800 gimplify_and_add (t, &seq);
801 }
802 continue;
803 }
804 if (known_eq (simd_clone_subparts (TREE_TYPE (arg)),
805 node->simdclone->simdlen))
806 {
807 tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
808 tree ptr = build_fold_addr_expr (array);
809 tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
810 build_int_cst (ptype, 0));
811 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
812 gimplify_and_add (t, &seq);
813 }
814 else
815 {
816 unsigned int simdlen = simd_clone_subparts (TREE_TYPE (arg));
817 unsigned int times = vector_unroll_factor (node->simdclone->simdlen,
818 simdlen);
819 tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
820 for (k = 0; k < times; k++)
821 {
822 tree ptr = build_fold_addr_expr (array);
823 int elemsize;
824 if (k)
825 {
826 arg = DECL_CHAIN (arg);
827 j++;
828 }
829 tree elemtype = TREE_TYPE (TREE_TYPE (arg));
830 elemsize = GET_MODE_SIZE (SCALAR_TYPE_MODE (elemtype));
831 tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
832 build_int_cst (ptype, k * elemsize * simdlen));
833 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
834 gimplify_and_add (t, &seq);
835 }
836 }
837 }
838 return seq;
839 }
840
841 /* Callback info for ipa_simd_modify_stmt_ops below. */
842
843 struct modify_stmt_info {
844 ipa_param_body_adjustments *adjustments;
845 gimple *stmt;
846 gimple *after_stmt;
847 /* True if the parent statement was modified by
848 ipa_simd_modify_stmt_ops. */
849 bool modified;
850 };
851
852 /* Callback for walk_gimple_op.
853
854 Adjust operands from a given statement as specified in the
855 adjustments vector in the callback data. */
856
857 static tree
858 ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
859 {
860 struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
861 struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
862 tree *orig_tp = tp;
863 if (TREE_CODE (*tp) == ADDR_EXPR)
864 tp = &TREE_OPERAND (*tp, 0);
865
866 if (TREE_CODE (*tp) == BIT_FIELD_REF
867 || TREE_CODE (*tp) == IMAGPART_EXPR
868 || TREE_CODE (*tp) == REALPART_EXPR)
869 tp = &TREE_OPERAND (*tp, 0);
870
871 tree repl = NULL_TREE;
872 ipa_param_body_replacement *pbr = NULL;
873
874 if (TREE_CODE (*tp) == PARM_DECL)
875 {
876 pbr = info->adjustments->get_expr_replacement (*tp, true);
877 if (pbr)
878 repl = pbr->repl;
879 }
880 else if (TYPE_P (*tp))
881 *walk_subtrees = 0;
882
883 if (repl)
884 repl = unshare_expr (repl);
885 else
886 {
887 if (tp != orig_tp)
888 {
889 *walk_subtrees = 0;
890 bool modified = info->modified;
891 info->modified = false;
892 walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset);
893 if (!info->modified)
894 {
895 info->modified = modified;
896 return NULL_TREE;
897 }
898 info->modified = modified;
899 repl = *tp;
900 }
901 else
902 return NULL_TREE;
903 }
904
905 if (tp != orig_tp)
906 {
907 if (gimple_code (info->stmt) == GIMPLE_PHI
908 && pbr
909 && TREE_CODE (*orig_tp) == ADDR_EXPR
910 && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL
911 && pbr->dummy)
912 {
913 gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME);
914 *orig_tp = pbr->dummy;
915 info->modified = true;
916 return NULL_TREE;
917 }
918
919 repl = build_fold_addr_expr (repl);
920 gimple *stmt;
921 if (is_gimple_debug (info->stmt))
922 {
923 tree vexpr = build_debug_expr_decl (TREE_TYPE (repl));
924 stmt = gimple_build_debug_source_bind (vexpr, repl, NULL);
925 repl = vexpr;
926 }
927 else
928 {
929 stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
930 repl = gimple_assign_lhs (stmt);
931 }
932 gimple_stmt_iterator gsi;
933 if (gimple_code (info->stmt) == GIMPLE_PHI)
934 {
935 if (info->after_stmt)
936 gsi = gsi_for_stmt (info->after_stmt);
937 else
938 gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
939 /* Cache SSA_NAME for next time. */
940 if (pbr
941 && TREE_CODE (*orig_tp) == ADDR_EXPR
942 && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL)
943 {
944 gcc_assert (!pbr->dummy);
945 pbr->dummy = repl;
946 }
947 }
948 else
949 gsi = gsi_for_stmt (info->stmt);
950 if (info->after_stmt)
951 gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
952 else
953 gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
954 if (gimple_code (info->stmt) == GIMPLE_PHI)
955 info->after_stmt = stmt;
956 *orig_tp = repl;
957 }
958 else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
959 {
960 tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
961 *tp = vce;
962 }
963 else
964 *tp = repl;
965
966 info->modified = true;
967 return NULL_TREE;
968 }
969
970 /* Traverse the function body and perform all modifications as
971 described in ADJUSTMENTS. At function return, ADJUSTMENTS will be
972 modified such that the replacement/reduction value will now be an
973 offset into the corresponding simd_array.
974
975 This function will replace all function argument uses with their
976 corresponding simd array elements, and ajust the return values
977 accordingly. */
978
979 static void
980 ipa_simd_modify_function_body (struct cgraph_node *node,
981 ipa_param_body_adjustments *adjustments,
982 tree retval_array, tree iter)
983 {
984 basic_block bb;
985 unsigned int i, j;
986
987
988 /* Register replacements for every function argument use to an offset into
989 the corresponding simd_array. */
990 for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
991 {
992 if (!node->simdclone->args[i].vector_arg
993 || (*adjustments->m_adj_params)[j].user_flag)
994 continue;
995
996 tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
997 tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
998 tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
999 iter, NULL_TREE, NULL_TREE);
1000 adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
1001
1002 if (multiple_p (node->simdclone->simdlen, simd_clone_subparts (vectype)))
1003 j += vector_unroll_factor (node->simdclone->simdlen,
1004 simd_clone_subparts (vectype)) - 1;
1005 }
1006
1007 tree name;
1008 FOR_EACH_SSA_NAME (i, name, cfun)
1009 {
1010 tree base_var;
1011 if (SSA_NAME_VAR (name)
1012 && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
1013 && (base_var
1014 = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
1015 {
1016 if (SSA_NAME_IS_DEFAULT_DEF (name))
1017 {
1018 tree old_decl = SSA_NAME_VAR (name);
1019 bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1020 gimple_stmt_iterator gsi = gsi_after_labels (bb);
1021 tree repl = adjustments->lookup_replacement (old_decl, 0);
1022 gcc_checking_assert (repl);
1023 repl = unshare_expr (repl);
1024 set_ssa_default_def (cfun, old_decl, NULL_TREE);
1025 SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1026 SSA_NAME_IS_DEFAULT_DEF (name) = 0;
1027 gimple *stmt = gimple_build_assign (name, repl);
1028 gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1029 }
1030 else
1031 SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1032 }
1033 }
1034
1035 struct modify_stmt_info info;
1036 info.adjustments = adjustments;
1037
1038 FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
1039 {
1040 gimple_stmt_iterator gsi;
1041
1042 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1043 {
1044 gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
1045 int i, n = gimple_phi_num_args (phi);
1046 info.stmt = phi;
1047 info.after_stmt = NULL;
1048 struct walk_stmt_info wi;
1049 memset (&wi, 0, sizeof (wi));
1050 info.modified = false;
1051 wi.info = &info;
1052 for (i = 0; i < n; ++i)
1053 {
1054 int walk_subtrees = 1;
1055 tree arg = gimple_phi_arg_def (phi, i);
1056 tree op = arg;
1057 ipa_simd_modify_stmt_ops (&op, &walk_subtrees, &wi);
1058 if (op != arg)
1059 {
1060 SET_PHI_ARG_DEF (phi, i, op);
1061 gcc_assert (TREE_CODE (op) == SSA_NAME);
1062 if (gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL)
1063 SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
1064 }
1065 }
1066 }
1067
1068 gsi = gsi_start_bb (bb);
1069 while (!gsi_end_p (gsi))
1070 {
1071 gimple *stmt = gsi_stmt (gsi);
1072 info.stmt = stmt;
1073 info.after_stmt = NULL;
1074 struct walk_stmt_info wi;
1075
1076 memset (&wi, 0, sizeof (wi));
1077 info.modified = false;
1078 wi.info = &info;
1079 walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
1080
1081 if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
1082 {
1083 tree retval = gimple_return_retval (return_stmt);
1084 edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
1085 e->flags |= EDGE_FALLTHRU;
1086 if (!retval)
1087 {
1088 gsi_remove (&gsi, true);
1089 continue;
1090 }
1091
1092 /* Replace `return foo' with `retval_array[iter] = foo'. */
1093 tree ref = build4 (ARRAY_REF, TREE_TYPE (retval),
1094 retval_array, iter, NULL, NULL);
1095 stmt = gimple_build_assign (ref, retval);
1096 gsi_replace (&gsi, stmt, true);
1097 info.modified = true;
1098 }
1099
1100 if (info.modified)
1101 {
1102 update_stmt (stmt);
1103 /* If the above changed the var of a debug bind into something
1104 different, remove the debug stmt. We could also for all the
1105 replaced parameters add VAR_DECLs for debug info purposes,
1106 add debug stmts for those to be the simd array accesses and
1107 replace debug stmt var operand with that var. Debugging of
1108 vectorized loops doesn't work too well, so don't bother for
1109 now. */
1110 if ((gimple_debug_bind_p (stmt)
1111 && !DECL_P (gimple_debug_bind_get_var (stmt)))
1112 || (gimple_debug_source_bind_p (stmt)
1113 && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
1114 {
1115 gsi_remove (&gsi, true);
1116 continue;
1117 }
1118 if (maybe_clean_eh_stmt (stmt))
1119 gimple_purge_dead_eh_edges (gimple_bb (stmt));
1120 }
1121 gsi_next (&gsi);
1122 }
1123 }
1124 }
1125
1126 /* Helper function of simd_clone_adjust, return linear step addend
1127 of Ith argument. */
1128
1129 static tree
1130 simd_clone_linear_addend (struct cgraph_node *node, unsigned int i,
1131 tree addtype, basic_block entry_bb)
1132 {
1133 tree ptype = NULL_TREE;
1134 switch (node->simdclone->args[i].arg_type)
1135 {
1136 case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
1137 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
1138 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1139 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
1140 return build_int_cst (addtype, node->simdclone->args[i].linear_step);
1141 case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
1142 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
1143 ptype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1144 break;
1145 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1146 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1147 ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg));
1148 break;
1149 default:
1150 gcc_unreachable ();
1151 }
1152
1153 unsigned int idx = node->simdclone->args[i].linear_step;
1154 tree arg = node->simdclone->args[idx].orig_arg;
1155 gcc_assert (is_gimple_reg_type (TREE_TYPE (arg)));
1156 gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1157 gimple *g;
1158 tree ret;
1159 if (is_gimple_reg (arg))
1160 ret = get_or_create_ssa_default_def (cfun, arg);
1161 else
1162 {
1163 g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
1164 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1165 ret = gimple_assign_lhs (g);
1166 }
1167 if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
1168 {
1169 g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))),
1170 build_simple_mem_ref (ret));
1171 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1172 ret = gimple_assign_lhs (g);
1173 }
1174 if (!useless_type_conversion_p (addtype, TREE_TYPE (ret)))
1175 {
1176 g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret);
1177 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1178 ret = gimple_assign_lhs (g);
1179 }
1180 if (POINTER_TYPE_P (ptype))
1181 {
1182 tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype));
1183 if (size && TREE_CODE (size) == INTEGER_CST)
1184 {
1185 g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR,
1186 ret, fold_convert (addtype, size));
1187 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1188 ret = gimple_assign_lhs (g);
1189 }
1190 }
1191 return ret;
1192 }
1193
1194 /* Adjust the argument types in NODE to their appropriate vector
1195 counterparts. */
1196
1197 static void
1198 simd_clone_adjust (struct cgraph_node *node)
1199 {
1200 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
1201
1202 TREE_TYPE (node->decl) = build_distinct_type_copy (TREE_TYPE (node->decl));
1203 targetm.simd_clone.adjust (node);
1204
1205 tree retval = simd_clone_adjust_return_type (node);
1206 ipa_param_body_adjustments *adjustments
1207 = simd_clone_adjust_argument_types (node);
1208 gcc_assert (adjustments);
1209
1210 push_gimplify_context ();
1211
1212 gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments);
1213
1214 /* Adjust all uses of vector arguments accordingly. Adjust all
1215 return values accordingly. */
1216 tree iter = create_tmp_var (unsigned_type_node, "iter");
1217 tree iter1 = make_ssa_name (iter);
1218 tree iter2 = NULL_TREE;
1219 ipa_simd_modify_function_body (node, adjustments, retval, iter1);
1220 delete adjustments;
1221
1222 /* Initialize the iteration variable. */
1223 basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1224 basic_block body_bb = split_block_after_labels (entry_bb)->dest;
1225 gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1226 /* Insert the SIMD array and iv initialization at function
1227 entry. */
1228 gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
1229
1230 pop_gimplify_context (NULL);
1231
1232 gimple *g;
1233 basic_block incr_bb = NULL;
1234 class loop *loop = NULL;
1235
1236 /* Create a new BB right before the original exit BB, to hold the
1237 iteration increment and the condition/branch. */
1238 if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1239 {
1240 basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
1241 incr_bb = create_empty_bb (orig_exit);
1242 incr_bb->count = profile_count::zero ();
1243 add_bb_to_loop (incr_bb, body_bb->loop_father);
1244 while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1245 {
1246 edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1247 redirect_edge_succ (e, incr_bb);
1248 incr_bb->count += e->count ();
1249 }
1250 }
1251 else if (node->simdclone->inbranch)
1252 {
1253 incr_bb = create_empty_bb (entry_bb);
1254 incr_bb->count = profile_count::zero ();
1255 add_bb_to_loop (incr_bb, body_bb->loop_father);
1256 }
1257
1258 if (incr_bb)
1259 {
1260 make_single_succ_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1261 gsi = gsi_last_bb (incr_bb);
1262 iter2 = make_ssa_name (iter);
1263 g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
1264 build_int_cst (unsigned_type_node, 1));
1265 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1266
1267 /* Mostly annotate the loop for the vectorizer (the rest is done
1268 below). */
1269 loop = alloc_loop ();
1270 cfun->has_force_vectorize_loops = true;
1271 /* For now, simlen is always constant. */
1272 loop->safelen = node->simdclone->simdlen.to_constant ();
1273 loop->force_vectorize = true;
1274 loop->header = body_bb;
1275 }
1276
1277 /* Branch around the body if the mask applies. */
1278 if (node->simdclone->inbranch)
1279 {
1280 gsi = gsi_last_bb (loop->header);
1281 tree mask_array
1282 = node->simdclone->args[node->simdclone->nargs - 1].simd_array;
1283 tree mask;
1284 if (node->simdclone->mask_mode != VOIDmode)
1285 {
1286 tree shift_cnt;
1287 if (mask_array == NULL_TREE)
1288 {
1289 tree arg = node->simdclone->args[node->simdclone->nargs
1290 - 1].vector_arg;
1291 mask = get_or_create_ssa_default_def (cfun, arg);
1292 shift_cnt = iter1;
1293 }
1294 else
1295 {
1296 tree maskt = TREE_TYPE (mask_array);
1297 int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt)));
1298 /* For now, c must be constant here. */
1299 c = exact_div (node->simdclone->simdlen, c + 1).to_constant ();
1300 int s = exact_log2 (c);
1301 gcc_assert (s > 0);
1302 c--;
1303 tree idx = make_ssa_name (TREE_TYPE (iter1));
1304 g = gimple_build_assign (idx, RSHIFT_EXPR, iter1,
1305 build_int_cst (NULL_TREE, s));
1306 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1307 mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1308 tree aref = build4 (ARRAY_REF,
1309 TREE_TYPE (TREE_TYPE (mask_array)),
1310 mask_array, idx, NULL, NULL);
1311 g = gimple_build_assign (mask, aref);
1312 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1313 shift_cnt = make_ssa_name (TREE_TYPE (iter1));
1314 g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1,
1315 build_int_cst (TREE_TYPE (iter1), c));
1316 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1317 }
1318 tree shift_cnt_conv = shift_cnt;
1319 if (!useless_type_conversion_p (TREE_TYPE (mask),
1320 TREE_TYPE (shift_cnt)))
1321 {
1322 shift_cnt_conv = make_ssa_name (TREE_TYPE (mask));
1323 g = gimple_build_assign (shift_cnt_conv, NOP_EXPR, shift_cnt);
1324 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1325 }
1326 g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1327 RSHIFT_EXPR, mask, shift_cnt_conv);
1328 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1329 mask = gimple_assign_lhs (g);
1330 g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1331 BIT_AND_EXPR, mask,
1332 build_int_cst (TREE_TYPE (mask), 1));
1333 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1334 mask = gimple_assign_lhs (g);
1335 }
1336 else
1337 {
1338 mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1339 tree aref = build4 (ARRAY_REF,
1340 TREE_TYPE (TREE_TYPE (mask_array)),
1341 mask_array, iter1, NULL, NULL);
1342 g = gimple_build_assign (mask, aref);
1343 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1344 int bitsize = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (aref)));
1345 if (!INTEGRAL_TYPE_P (TREE_TYPE (aref)))
1346 {
1347 aref = build1 (VIEW_CONVERT_EXPR,
1348 build_nonstandard_integer_type (bitsize, 0),
1349 mask);
1350 mask = make_ssa_name (TREE_TYPE (aref));
1351 g = gimple_build_assign (mask, aref);
1352 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1353 }
1354 }
1355
1356 g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)),
1357 NULL, NULL);
1358 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1359 edge e = make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE);
1360 e->probability = profile_probability::unlikely ().guessed ();
1361 incr_bb->count += e->count ();
1362 edge fallthru = FALLTHRU_EDGE (loop->header);
1363 fallthru->flags = EDGE_FALSE_VALUE;
1364 fallthru->probability = profile_probability::likely ().guessed ();
1365 }
1366
1367 basic_block latch_bb = NULL;
1368 basic_block new_exit_bb = NULL;
1369
1370 /* Generate the condition. */
1371 if (incr_bb)
1372 {
1373 gsi = gsi_last_bb (incr_bb);
1374 g = gimple_build_cond (LT_EXPR, iter2,
1375 build_int_cst (unsigned_type_node,
1376 node->simdclone->simdlen),
1377 NULL, NULL);
1378 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1379 edge e = split_block (incr_bb, gsi_stmt (gsi));
1380 latch_bb = e->dest;
1381 new_exit_bb = split_block_after_labels (latch_bb)->dest;
1382 loop->latch = latch_bb;
1383
1384 redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
1385
1386 edge new_e = make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
1387
1388 /* FIXME: Do we need to distribute probabilities for the conditional? */
1389 new_e->probability = profile_probability::guessed_never ();
1390 /* The successor of incr_bb is already pointing to latch_bb; just
1391 change the flags.
1392 make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE); */
1393 FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
1394 }
1395
1396 gphi *phi = create_phi_node (iter1, body_bb);
1397 edge preheader_edge = find_edge (entry_bb, body_bb);
1398 edge latch_edge = NULL;
1399 add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
1400 UNKNOWN_LOCATION);
1401 if (incr_bb)
1402 {
1403 latch_edge = single_succ_edge (latch_bb);
1404 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1405
1406 /* Generate the new return. */
1407 gsi = gsi_last_bb (new_exit_bb);
1408 if (retval
1409 && TREE_CODE (retval) == VIEW_CONVERT_EXPR
1410 && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
1411 retval = TREE_OPERAND (retval, 0);
1412 else if (retval)
1413 {
1414 retval = build1 (VIEW_CONVERT_EXPR,
1415 TREE_TYPE (TREE_TYPE (node->decl)),
1416 retval);
1417 retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
1418 false, GSI_CONTINUE_LINKING);
1419 }
1420 g = gimple_build_return (retval);
1421 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1422 }
1423
1424 /* Handle aligned clauses by replacing default defs of the aligned
1425 uniform args with __builtin_assume_aligned (arg_N(D), alignment)
1426 lhs. Handle linear by adding PHIs. */
1427 for (unsigned i = 0; i < node->simdclone->nargs; i++)
1428 if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1429 && (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg)
1430 || !is_gimple_reg_type
1431 (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1432 {
1433 tree orig_arg = node->simdclone->args[i].orig_arg;
1434 if (is_gimple_reg_type (TREE_TYPE (orig_arg)))
1435 iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1436 else
1437 {
1438 iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg));
1439 gimple_add_tmp_var (iter1);
1440 }
1441 gsi = gsi_after_labels (entry_bb);
1442 g = gimple_build_assign (iter1, orig_arg);
1443 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1444 gsi = gsi_after_labels (body_bb);
1445 g = gimple_build_assign (orig_arg, iter1);
1446 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1447 }
1448 else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1449 && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg)
1450 && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1451 == REFERENCE_TYPE
1452 && TREE_ADDRESSABLE
1453 (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1454 {
1455 tree orig_arg = node->simdclone->args[i].orig_arg;
1456 tree def = ssa_default_def (cfun, orig_arg);
1457 if (def && !has_zero_uses (def))
1458 {
1459 iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg)));
1460 gimple_add_tmp_var (iter1);
1461 gsi = gsi_after_labels (entry_bb);
1462 g = gimple_build_assign (iter1, build_simple_mem_ref (def));
1463 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1464 gsi = gsi_after_labels (body_bb);
1465 g = gimple_build_assign (build_simple_mem_ref (def), iter1);
1466 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1467 }
1468 }
1469 else if (node->simdclone->args[i].alignment
1470 && node->simdclone->args[i].arg_type
1471 == SIMD_CLONE_ARG_TYPE_UNIFORM
1472 && (node->simdclone->args[i].alignment
1473 & (node->simdclone->args[i].alignment - 1)) == 0
1474 && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1475 == POINTER_TYPE)
1476 {
1477 unsigned int alignment = node->simdclone->args[i].alignment;
1478 tree orig_arg = node->simdclone->args[i].orig_arg;
1479 tree def = ssa_default_def (cfun, orig_arg);
1480 if (def && !has_zero_uses (def))
1481 {
1482 tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
1483 gimple_seq seq = NULL;
1484 bool need_cvt = false;
1485 gcall *call
1486 = gimple_build_call (fn, 2, def, size_int (alignment));
1487 g = call;
1488 if (!useless_type_conversion_p (TREE_TYPE (orig_arg),
1489 ptr_type_node))
1490 need_cvt = true;
1491 tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg);
1492 gimple_call_set_lhs (g, t);
1493 gimple_seq_add_stmt_without_update (&seq, g);
1494 if (need_cvt)
1495 {
1496 t = make_ssa_name (orig_arg);
1497 g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g));
1498 gimple_seq_add_stmt_without_update (&seq, g);
1499 }
1500 gsi_insert_seq_on_edge_immediate
1501 (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
1502
1503 entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1504 node->create_edge (cgraph_node::get_create (fn),
1505 call, entry_bb->count);
1506
1507 imm_use_iterator iter;
1508 use_operand_p use_p;
1509 gimple *use_stmt;
1510 tree repl = gimple_get_lhs (g);
1511 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1512 if (is_gimple_debug (use_stmt) || use_stmt == call)
1513 continue;
1514 else
1515 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1516 SET_USE (use_p, repl);
1517 }
1518 }
1519 else if ((node->simdclone->args[i].arg_type
1520 == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
1521 || (node->simdclone->args[i].arg_type
1522 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
1523 || (node->simdclone->args[i].arg_type
1524 == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP)
1525 || (node->simdclone->args[i].arg_type
1526 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP))
1527 {
1528 tree orig_arg = node->simdclone->args[i].orig_arg;
1529 gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1530 || POINTER_TYPE_P (TREE_TYPE (orig_arg)));
1531 tree def = NULL_TREE;
1532 if (TREE_ADDRESSABLE (orig_arg))
1533 {
1534 def = make_ssa_name (TREE_TYPE (orig_arg));
1535 iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1536 if (incr_bb)
1537 iter2 = make_ssa_name (TREE_TYPE (orig_arg));
1538 gsi = gsi_after_labels (entry_bb);
1539 g = gimple_build_assign (def, orig_arg);
1540 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1541 }
1542 else
1543 {
1544 def = ssa_default_def (cfun, orig_arg);
1545 if (!def || has_zero_uses (def))
1546 def = NULL_TREE;
1547 else
1548 {
1549 iter1 = make_ssa_name (orig_arg);
1550 if (incr_bb)
1551 iter2 = make_ssa_name (orig_arg);
1552 }
1553 }
1554 if (def)
1555 {
1556 phi = create_phi_node (iter1, body_bb);
1557 add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
1558 if (incr_bb)
1559 {
1560 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1561 enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1562 ? PLUS_EXPR : POINTER_PLUS_EXPR;
1563 tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1564 ? TREE_TYPE (orig_arg) : sizetype;
1565 tree addcst = simd_clone_linear_addend (node, i, addtype,
1566 entry_bb);
1567 gsi = gsi_last_bb (incr_bb);
1568 g = gimple_build_assign (iter2, code, iter1, addcst);
1569 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1570 }
1571
1572 imm_use_iterator iter;
1573 use_operand_p use_p;
1574 gimple *use_stmt;
1575 if (TREE_ADDRESSABLE (orig_arg))
1576 {
1577 gsi = gsi_after_labels (body_bb);
1578 g = gimple_build_assign (orig_arg, iter1);
1579 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1580 }
1581 else
1582 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1583 if (use_stmt == phi)
1584 continue;
1585 else
1586 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1587 SET_USE (use_p, iter1);
1588 }
1589 }
1590 else if (node->simdclone->args[i].arg_type
1591 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP
1592 || (node->simdclone->args[i].arg_type
1593 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP))
1594 {
1595 tree orig_arg = node->simdclone->args[i].orig_arg;
1596 tree def = ssa_default_def (cfun, orig_arg);
1597 gcc_assert (!TREE_ADDRESSABLE (orig_arg)
1598 && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE);
1599 if (def && !has_zero_uses (def))
1600 {
1601 tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
1602 iter1 = make_ssa_name (orig_arg);
1603 if (incr_bb)
1604 iter2 = make_ssa_name (orig_arg);
1605 tree iter3 = make_ssa_name (rtype);
1606 tree iter4 = make_ssa_name (rtype);
1607 tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
1608 gsi = gsi_after_labels (entry_bb);
1609 gimple *load
1610 = gimple_build_assign (iter3, build_simple_mem_ref (def));
1611 gsi_insert_before (&gsi, load, GSI_NEW_STMT);
1612
1613 tree array = node->simdclone->args[i].simd_array;
1614 TREE_ADDRESSABLE (array) = 1;
1615 tree ptr = build_fold_addr_expr (array);
1616 phi = create_phi_node (iter1, body_bb);
1617 add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
1618 if (incr_bb)
1619 {
1620 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1621 g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
1622 TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
1623 gsi = gsi_last_bb (incr_bb);
1624 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1625 }
1626
1627 phi = create_phi_node (iter4, body_bb);
1628 add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
1629 if (incr_bb)
1630 {
1631 add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
1632 enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1633 ? PLUS_EXPR : POINTER_PLUS_EXPR;
1634 tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1635 ? TREE_TYPE (iter3) : sizetype;
1636 tree addcst = simd_clone_linear_addend (node, i, addtype,
1637 entry_bb);
1638 g = gimple_build_assign (iter5, code, iter4, addcst);
1639 gsi = gsi_last_bb (incr_bb);
1640 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1641 }
1642
1643 g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
1644 gsi = gsi_after_labels (body_bb);
1645 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1646
1647 imm_use_iterator iter;
1648 use_operand_p use_p;
1649 gimple *use_stmt;
1650 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1651 if (use_stmt == load)
1652 continue;
1653 else
1654 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1655 SET_USE (use_p, iter1);
1656
1657 if (!TYPE_READONLY (rtype) && incr_bb)
1658 {
1659 tree v = make_ssa_name (rtype);
1660 tree aref = build4 (ARRAY_REF, rtype, array,
1661 size_zero_node, NULL_TREE,
1662 NULL_TREE);
1663 gsi = gsi_after_labels (new_exit_bb);
1664 g = gimple_build_assign (v, aref);
1665 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1666 g = gimple_build_assign (build_simple_mem_ref (def), v);
1667 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1668 }
1669 }
1670 }
1671
1672 calculate_dominance_info (CDI_DOMINATORS);
1673 if (loop)
1674 add_loop (loop, loop->header->loop_father);
1675 update_ssa (TODO_update_ssa);
1676
1677 pop_cfun ();
1678 }
1679
1680 /* If the function in NODE is tagged as an elemental SIMD function,
1681 create the appropriate SIMD clones. */
1682
1683 void
1684 expand_simd_clones (struct cgraph_node *node)
1685 {
1686 tree attr = lookup_attribute ("omp declare simd",
1687 DECL_ATTRIBUTES (node->decl));
1688 if (attr == NULL_TREE
1689 || node->inlined_to
1690 || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
1691 return;
1692
1693 /* Ignore
1694 #pragma omp declare simd
1695 extern int foo ();
1696 in C, there we don't know the argument types at all. */
1697 if (!node->definition
1698 && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE)
1699 return;
1700
1701 /* Call this before creating clone_info, as it might ggc_collect. */
1702 if (node->definition && node->has_gimple_body_p ())
1703 node->get_body ();
1704
1705 do
1706 {
1707 /* Start with parsing the "omp declare simd" attribute(s). */
1708 bool inbranch_clause_specified;
1709 struct cgraph_simd_clone *clone_info
1710 = simd_clone_clauses_extract (node, TREE_VALUE (attr),
1711 &inbranch_clause_specified);
1712 if (clone_info == NULL)
1713 continue;
1714
1715 poly_uint64 orig_simdlen = clone_info->simdlen;
1716 tree base_type = simd_clone_compute_base_data_type (node, clone_info);
1717 /* The target can return 0 (no simd clones should be created),
1718 1 (just one ISA of simd clones should be created) or higher
1719 count of ISA variants. In that case, clone_info is initialized
1720 for the first ISA variant. */
1721 int count
1722 = targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info,
1723 base_type, 0);
1724 if (count == 0)
1725 continue;
1726
1727 /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED,
1728 also create one inbranch and one !inbranch clone of it. */
1729 for (int i = 0; i < count * 2; i++)
1730 {
1731 struct cgraph_simd_clone *clone = clone_info;
1732 if (inbranch_clause_specified && (i & 1) != 0)
1733 continue;
1734
1735 if (i != 0)
1736 {
1737 clone = simd_clone_struct_alloc (clone_info->nargs
1738 + ((i & 1) != 0));
1739 simd_clone_struct_copy (clone, clone_info);
1740 /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen
1741 and simd_clone_adjust_argument_types did to the first
1742 clone's info. */
1743 clone->nargs -= clone_info->inbranch;
1744 clone->simdlen = orig_simdlen;
1745 /* And call the target hook again to get the right ISA. */
1746 targetm.simd_clone.compute_vecsize_and_simdlen (node, clone,
1747 base_type,
1748 i / 2);
1749 if ((i & 1) != 0)
1750 clone->inbranch = 1;
1751 }
1752
1753 /* simd_clone_mangle might fail if such a clone has been created
1754 already. */
1755 tree id = simd_clone_mangle (node, clone);
1756 if (id == NULL_TREE)
1757 {
1758 if (i == 0)
1759 clone->nargs += clone->inbranch;
1760 continue;
1761 }
1762
1763 /* Only when we are sure we want to create the clone actually
1764 clone the function (or definitions) or create another
1765 extern FUNCTION_DECL (for prototypes without definitions). */
1766 struct cgraph_node *n = simd_clone_create (node);
1767 if (n == NULL)
1768 {
1769 if (i == 0)
1770 clone->nargs += clone->inbranch;
1771 continue;
1772 }
1773
1774 n->simdclone = clone;
1775 clone->origin = node;
1776 clone->next_clone = NULL;
1777 if (node->simd_clones == NULL)
1778 {
1779 clone->prev_clone = n;
1780 node->simd_clones = n;
1781 }
1782 else
1783 {
1784 clone->prev_clone = node->simd_clones->simdclone->prev_clone;
1785 clone->prev_clone->simdclone->next_clone = n;
1786 node->simd_clones->simdclone->prev_clone = n;
1787 }
1788 symtab->change_decl_assembler_name (n->decl, id);
1789 /* And finally adjust the return type, parameters and for
1790 definitions also function body. */
1791 if (node->definition)
1792 simd_clone_adjust (n);
1793 else
1794 {
1795 TREE_TYPE (n->decl)
1796 = build_distinct_type_copy (TREE_TYPE (n->decl));
1797 targetm.simd_clone.adjust (n);
1798 simd_clone_adjust_return_type (n);
1799 simd_clone_adjust_argument_types (n);
1800 }
1801 }
1802 }
1803 while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
1804 }
1805
1806 /* Entry point for IPA simd clone creation pass. */
1807
1808 static unsigned int
1809 ipa_omp_simd_clone (void)
1810 {
1811 struct cgraph_node *node;
1812 FOR_EACH_FUNCTION (node)
1813 expand_simd_clones (node);
1814 return 0;
1815 }
1816
1817 namespace {
1818
1819 const pass_data pass_data_omp_simd_clone =
1820 {
1821 SIMPLE_IPA_PASS, /* type */
1822 "simdclone", /* name */
1823 OPTGROUP_OMP, /* optinfo_flags */
1824 TV_NONE, /* tv_id */
1825 ( PROP_ssa | PROP_cfg ), /* properties_required */
1826 0, /* properties_provided */
1827 0, /* properties_destroyed */
1828 0, /* todo_flags_start */
1829 0, /* todo_flags_finish */
1830 };
1831
1832 class pass_omp_simd_clone : public simple_ipa_opt_pass
1833 {
1834 public:
1835 pass_omp_simd_clone(gcc::context *ctxt)
1836 : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt)
1837 {}
1838
1839 /* opt_pass methods: */
1840 bool gate (function *) final override;
1841 unsigned int execute (function *) final override
1842 {
1843 return ipa_omp_simd_clone ();
1844 }
1845 };
1846
1847 bool
1848 pass_omp_simd_clone::gate (function *)
1849 {
1850 return targetm.simd_clone.compute_vecsize_and_simdlen != NULL;
1851 }
1852
1853 } // anon namespace
1854
1855 simple_ipa_opt_pass *
1856 make_pass_omp_simd_clone (gcc::context *ctxt)
1857 {
1858 return new pass_omp_simd_clone (ctxt);
1859 }