]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/omp-simd-clone.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / omp-simd-clone.c
1 /* OMP constructs' SIMD clone supporting code.
2
3 Copyright (C) 2005-2021 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 veclen = exact_div (veclen, GET_MODE_BITSIZE (SCALAR_TYPE_MODE (t)));
508 if (multiple_p (veclen, node->simdclone->simdlen))
509 veclen = node->simdclone->simdlen;
510 if (POINTER_TYPE_P (t))
511 t = pointer_sized_int_node;
512 if (known_eq (veclen, node->simdclone->simdlen))
513 t = build_vector_type (t, node->simdclone->simdlen);
514 else
515 {
516 t = build_vector_type (t, veclen);
517 t = build_array_type_nelts (t, exact_div (node->simdclone->simdlen,
518 veclen));
519 }
520 TREE_TYPE (TREE_TYPE (fndecl)) = t;
521 if (!node->definition)
522 return NULL_TREE;
523
524 t = DECL_RESULT (fndecl);
525 /* Adjust the DECL_RESULT. */
526 gcc_assert (TREE_TYPE (t) != void_type_node);
527 TREE_TYPE (t) = TREE_TYPE (TREE_TYPE (fndecl));
528 relayout_decl (t);
529
530 tree atype = build_array_type_nelts (orig_rettype,
531 node->simdclone->simdlen);
532 if (maybe_ne (veclen, node->simdclone->simdlen))
533 return build1 (VIEW_CONVERT_EXPR, atype, t);
534
535 /* Set up a SIMD array to use as the return value. */
536 tree retval = create_tmp_var_raw (atype, "retval");
537 gimple_add_tmp_var (retval);
538 return retval;
539 }
540
541 /* Each vector argument has a corresponding array to be used locally
542 as part of the eventual loop. Create such temporary array and
543 return it.
544
545 PREFIX is the prefix to be used for the temporary.
546
547 TYPE is the inner element type.
548
549 SIMDLEN is the number of elements. */
550
551 static tree
552 create_tmp_simd_array (const char *prefix, tree type, poly_uint64 simdlen)
553 {
554 tree atype = build_array_type_nelts (type, simdlen);
555 tree avar = create_tmp_var_raw (atype, prefix);
556 gimple_add_tmp_var (avar);
557 return avar;
558 }
559
560 /* Modify the function argument types to their corresponding vector
561 counterparts if appropriate. Also, create one array for each simd
562 argument to be used locally when using the function arguments as
563 part of the loop.
564
565 NODE is the function whose arguments are to be adjusted.
566
567 If NODE does not represent function definition, returns NULL. Otherwise
568 returns an adjustment class that will be filled describing how the argument
569 declarations will be remapped. New arguments which are not to be remapped
570 are marked with USER_FLAG. */
571
572 static ipa_param_body_adjustments *
573 simd_clone_adjust_argument_types (struct cgraph_node *node)
574 {
575 auto_vec<tree> args;
576
577 if (node->definition)
578 push_function_arg_decls (&args, node->decl);
579 else
580 simd_clone_vector_of_formal_parm_types (&args, node->decl);
581 struct cgraph_simd_clone *sc = node->simdclone;
582 vec<ipa_adjusted_param, va_gc> *new_params = NULL;
583 vec_safe_reserve (new_params, sc->nargs);
584 unsigned i, j, k;
585 poly_uint64 veclen;
586
587 for (i = 0; i < sc->nargs; ++i)
588 {
589 ipa_adjusted_param adj;
590 memset (&adj, 0, sizeof (adj));
591 tree parm = args[i];
592 tree parm_type = node->definition ? TREE_TYPE (parm) : parm;
593 adj.base_index = i;
594 adj.prev_clone_index = i;
595
596 sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
597 sc->args[i].orig_type = parm_type;
598
599 switch (sc->args[i].arg_type)
600 {
601 default:
602 /* No adjustment necessary for scalar arguments. */
603 adj.op = IPA_PARAM_OP_COPY;
604 break;
605 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
606 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
607 if (node->definition)
608 sc->args[i].simd_array
609 = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
610 TREE_TYPE (parm_type),
611 sc->simdlen);
612 adj.op = IPA_PARAM_OP_COPY;
613 break;
614 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
615 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
616 case SIMD_CLONE_ARG_TYPE_VECTOR:
617 if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type))
618 veclen = sc->vecsize_int;
619 else
620 veclen = sc->vecsize_float;
621 veclen = exact_div (veclen,
622 GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type)));
623 if (multiple_p (veclen, sc->simdlen))
624 veclen = sc->simdlen;
625 adj.op = IPA_PARAM_OP_NEW;
626 adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
627 if (POINTER_TYPE_P (parm_type))
628 adj.type = build_vector_type (pointer_sized_int_node, veclen);
629 else
630 adj.type = build_vector_type (parm_type, veclen);
631 sc->args[i].vector_type = adj.type;
632 k = vector_unroll_factor (sc->simdlen, veclen);
633 for (j = 1; j < k; j++)
634 {
635 vec_safe_push (new_params, adj);
636 if (j == 1)
637 {
638 memset (&adj, 0, sizeof (adj));
639 adj.op = IPA_PARAM_OP_NEW;
640 adj.user_flag = 1;
641 adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
642 adj.base_index = i;
643 adj.prev_clone_index = i;
644 adj.type = sc->args[i].vector_type;
645 }
646 }
647
648 if (node->definition)
649 sc->args[i].simd_array
650 = create_tmp_simd_array (DECL_NAME (parm)
651 ? IDENTIFIER_POINTER (DECL_NAME (parm))
652 : NULL, parm_type, sc->simdlen);
653 }
654 vec_safe_push (new_params, adj);
655 }
656
657 if (sc->inbranch)
658 {
659 tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
660 ipa_adjusted_param adj;
661 memset (&adj, 0, sizeof (adj));
662 adj.op = IPA_PARAM_OP_NEW;
663 adj.user_flag = 1;
664 adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
665
666 adj.base_index = i;
667 adj.prev_clone_index = i;
668 if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
669 veclen = sc->vecsize_int;
670 else
671 veclen = sc->vecsize_float;
672 veclen = exact_div (veclen,
673 GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type)));
674 if (multiple_p (veclen, sc->simdlen))
675 veclen = sc->simdlen;
676 if (sc->mask_mode != VOIDmode)
677 adj.type
678 = lang_hooks.types.type_for_mode (sc->mask_mode, 1);
679 else if (POINTER_TYPE_P (base_type))
680 adj.type = build_vector_type (pointer_sized_int_node, veclen);
681 else
682 adj.type = build_vector_type (base_type, veclen);
683 vec_safe_push (new_params, adj);
684
685 k = vector_unroll_factor (sc->simdlen, veclen);
686 for (j = 1; j < k; j++)
687 vec_safe_push (new_params, adj);
688
689 /* We have previously allocated one extra entry for the mask. Use
690 it and fill it. */
691 sc->nargs++;
692 if (sc->mask_mode != VOIDmode)
693 base_type = boolean_type_node;
694 if (node->definition)
695 {
696 sc->args[i].orig_arg
697 = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type);
698 if (sc->mask_mode == VOIDmode)
699 sc->args[i].simd_array
700 = create_tmp_simd_array ("mask", base_type, sc->simdlen);
701 else if (k > 1)
702 sc->args[i].simd_array
703 = create_tmp_simd_array ("mask", adj.type, k);
704 else
705 sc->args[i].simd_array = NULL_TREE;
706 }
707 sc->args[i].orig_type = base_type;
708 sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK;
709 }
710
711 if (node->definition)
712 {
713 ipa_param_body_adjustments *adjustments
714 = new ipa_param_body_adjustments (new_params, node->decl);
715
716 adjustments->modify_formal_parameters ();
717 return adjustments;
718 }
719 else
720 {
721 tree new_arg_types = NULL_TREE, new_reversed;
722 bool last_parm_void = false;
723 if (args.length () > 0 && args.last () == void_type_node)
724 last_parm_void = true;
725
726 gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
727 j = vec_safe_length (new_params);
728 for (i = 0; i < j; i++)
729 {
730 struct ipa_adjusted_param *adj = &(*new_params)[i];
731 tree ptype;
732 if (adj->op == IPA_PARAM_OP_COPY)
733 ptype = args[adj->base_index];
734 else
735 ptype = adj->type;
736 new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types);
737 }
738 new_reversed = nreverse (new_arg_types);
739 if (last_parm_void)
740 {
741 if (new_reversed)
742 TREE_CHAIN (new_arg_types) = void_list_node;
743 else
744 new_reversed = void_list_node;
745 }
746 TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed;
747 return NULL;
748 }
749 }
750
751 /* Initialize and copy the function arguments in NODE to their
752 corresponding local simd arrays. Returns a fresh gimple_seq with
753 the instruction sequence generated. */
754
755 static gimple_seq
756 simd_clone_init_simd_arrays (struct cgraph_node *node,
757 ipa_param_body_adjustments *adjustments)
758 {
759 gimple_seq seq = NULL;
760 unsigned i = 0, j = 0, k;
761
762 for (tree arg = DECL_ARGUMENTS (node->decl);
763 arg;
764 arg = DECL_CHAIN (arg), i++, j++)
765 {
766 if ((*adjustments->m_adj_params)[j].op == IPA_PARAM_OP_COPY
767 || POINTER_TYPE_P (TREE_TYPE (arg)))
768 continue;
769
770 node->simdclone->args[i].vector_arg = arg;
771
772 tree array = node->simdclone->args[i].simd_array;
773 if (node->simdclone->mask_mode != VOIDmode
774 && node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
775 {
776 if (array == NULL_TREE)
777 continue;
778 unsigned int l
779 = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array))));
780 for (k = 0; k <= l; k++)
781 {
782 if (k)
783 {
784 arg = DECL_CHAIN (arg);
785 j++;
786 }
787 tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
788 array, size_int (k), NULL, NULL);
789 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
790 gimplify_and_add (t, &seq);
791 }
792 continue;
793 }
794 if (known_eq (simd_clone_subparts (TREE_TYPE (arg)),
795 node->simdclone->simdlen))
796 {
797 tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
798 tree ptr = build_fold_addr_expr (array);
799 tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
800 build_int_cst (ptype, 0));
801 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
802 gimplify_and_add (t, &seq);
803 }
804 else
805 {
806 unsigned int simdlen = simd_clone_subparts (TREE_TYPE (arg));
807 unsigned int times = vector_unroll_factor (node->simdclone->simdlen,
808 simdlen);
809 tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
810 for (k = 0; k < times; k++)
811 {
812 tree ptr = build_fold_addr_expr (array);
813 int elemsize;
814 if (k)
815 {
816 arg = DECL_CHAIN (arg);
817 j++;
818 }
819 tree elemtype = TREE_TYPE (TREE_TYPE (arg));
820 elemsize = GET_MODE_SIZE (SCALAR_TYPE_MODE (elemtype));
821 tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
822 build_int_cst (ptype, k * elemsize * simdlen));
823 t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
824 gimplify_and_add (t, &seq);
825 }
826 }
827 }
828 return seq;
829 }
830
831 /* Callback info for ipa_simd_modify_stmt_ops below. */
832
833 struct modify_stmt_info {
834 ipa_param_body_adjustments *adjustments;
835 gimple *stmt;
836 gimple *after_stmt;
837 /* True if the parent statement was modified by
838 ipa_simd_modify_stmt_ops. */
839 bool modified;
840 };
841
842 /* Callback for walk_gimple_op.
843
844 Adjust operands from a given statement as specified in the
845 adjustments vector in the callback data. */
846
847 static tree
848 ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
849 {
850 struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
851 struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
852 tree *orig_tp = tp;
853 if (TREE_CODE (*tp) == ADDR_EXPR)
854 tp = &TREE_OPERAND (*tp, 0);
855
856 if (TREE_CODE (*tp) == BIT_FIELD_REF
857 || TREE_CODE (*tp) == IMAGPART_EXPR
858 || TREE_CODE (*tp) == REALPART_EXPR)
859 tp = &TREE_OPERAND (*tp, 0);
860
861 tree repl = NULL_TREE;
862 ipa_param_body_replacement *pbr = NULL;
863
864 if (TREE_CODE (*tp) == PARM_DECL)
865 {
866 pbr = info->adjustments->get_expr_replacement (*tp, true);
867 if (pbr)
868 repl = pbr->repl;
869 }
870 else if (TYPE_P (*tp))
871 *walk_subtrees = 0;
872
873 if (repl)
874 repl = unshare_expr (repl);
875 else
876 {
877 if (tp != orig_tp)
878 {
879 *walk_subtrees = 0;
880 bool modified = info->modified;
881 info->modified = false;
882 walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset);
883 if (!info->modified)
884 {
885 info->modified = modified;
886 return NULL_TREE;
887 }
888 info->modified = modified;
889 repl = *tp;
890 }
891 else
892 return NULL_TREE;
893 }
894
895 if (tp != orig_tp)
896 {
897 if (gimple_code (info->stmt) == GIMPLE_PHI
898 && pbr
899 && TREE_CODE (*orig_tp) == ADDR_EXPR
900 && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL
901 && pbr->dummy)
902 {
903 gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME);
904 *orig_tp = pbr->dummy;
905 info->modified = true;
906 return NULL_TREE;
907 }
908
909 repl = build_fold_addr_expr (repl);
910 gimple *stmt;
911 if (is_gimple_debug (info->stmt))
912 {
913 tree vexpr = make_node (DEBUG_EXPR_DECL);
914 stmt = gimple_build_debug_source_bind (vexpr, repl, NULL);
915 DECL_ARTIFICIAL (vexpr) = 1;
916 TREE_TYPE (vexpr) = TREE_TYPE (repl);
917 SET_DECL_MODE (vexpr, TYPE_MODE (TREE_TYPE (repl)));
918 repl = vexpr;
919 }
920 else
921 {
922 stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
923 repl = gimple_assign_lhs (stmt);
924 }
925 gimple_stmt_iterator gsi;
926 if (gimple_code (info->stmt) == GIMPLE_PHI)
927 {
928 if (info->after_stmt)
929 gsi = gsi_for_stmt (info->after_stmt);
930 else
931 gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
932 /* Cache SSA_NAME for next time. */
933 if (pbr
934 && TREE_CODE (*orig_tp) == ADDR_EXPR
935 && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL)
936 {
937 gcc_assert (!pbr->dummy);
938 pbr->dummy = repl;
939 }
940 }
941 else
942 gsi = gsi_for_stmt (info->stmt);
943 if (info->after_stmt)
944 gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
945 else
946 gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
947 if (gimple_code (info->stmt) == GIMPLE_PHI)
948 info->after_stmt = stmt;
949 *orig_tp = repl;
950 }
951 else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
952 {
953 tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
954 *tp = vce;
955 }
956 else
957 *tp = repl;
958
959 info->modified = true;
960 return NULL_TREE;
961 }
962
963 /* Traverse the function body and perform all modifications as
964 described in ADJUSTMENTS. At function return, ADJUSTMENTS will be
965 modified such that the replacement/reduction value will now be an
966 offset into the corresponding simd_array.
967
968 This function will replace all function argument uses with their
969 corresponding simd array elements, and ajust the return values
970 accordingly. */
971
972 static void
973 ipa_simd_modify_function_body (struct cgraph_node *node,
974 ipa_param_body_adjustments *adjustments,
975 tree retval_array, tree iter)
976 {
977 basic_block bb;
978 unsigned int i, j;
979
980
981 /* Register replacements for every function argument use to an offset into
982 the corresponding simd_array. */
983 for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
984 {
985 if (!node->simdclone->args[i].vector_arg
986 || (*adjustments->m_adj_params)[j].user_flag)
987 continue;
988
989 tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
990 tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
991 tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
992 iter, NULL_TREE, NULL_TREE);
993 adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
994
995 if (multiple_p (node->simdclone->simdlen, simd_clone_subparts (vectype)))
996 j += vector_unroll_factor (node->simdclone->simdlen,
997 simd_clone_subparts (vectype)) - 1;
998 }
999
1000 tree name;
1001 FOR_EACH_SSA_NAME (i, name, cfun)
1002 {
1003 tree base_var;
1004 if (SSA_NAME_VAR (name)
1005 && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
1006 && (base_var
1007 = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
1008 {
1009 if (SSA_NAME_IS_DEFAULT_DEF (name))
1010 {
1011 tree old_decl = SSA_NAME_VAR (name);
1012 bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1013 gimple_stmt_iterator gsi = gsi_after_labels (bb);
1014 tree repl = adjustments->lookup_replacement (old_decl, 0);
1015 gcc_checking_assert (repl);
1016 repl = unshare_expr (repl);
1017 set_ssa_default_def (cfun, old_decl, NULL_TREE);
1018 SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1019 SSA_NAME_IS_DEFAULT_DEF (name) = 0;
1020 gimple *stmt = gimple_build_assign (name, repl);
1021 gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1022 }
1023 else
1024 SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1025 }
1026 }
1027
1028 struct modify_stmt_info info;
1029 info.adjustments = adjustments;
1030
1031 FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
1032 {
1033 gimple_stmt_iterator gsi;
1034
1035 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1036 {
1037 gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
1038 int i, n = gimple_phi_num_args (phi);
1039 info.stmt = phi;
1040 info.after_stmt = NULL;
1041 struct walk_stmt_info wi;
1042 memset (&wi, 0, sizeof (wi));
1043 info.modified = false;
1044 wi.info = &info;
1045 for (i = 0; i < n; ++i)
1046 {
1047 int walk_subtrees = 1;
1048 tree arg = gimple_phi_arg_def (phi, i);
1049 tree op = arg;
1050 ipa_simd_modify_stmt_ops (&op, &walk_subtrees, &wi);
1051 if (op != arg)
1052 {
1053 SET_PHI_ARG_DEF (phi, i, op);
1054 gcc_assert (TREE_CODE (op) == SSA_NAME);
1055 if (gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL)
1056 SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
1057 }
1058 }
1059 }
1060
1061 gsi = gsi_start_bb (bb);
1062 while (!gsi_end_p (gsi))
1063 {
1064 gimple *stmt = gsi_stmt (gsi);
1065 info.stmt = stmt;
1066 info.after_stmt = NULL;
1067 struct walk_stmt_info wi;
1068
1069 memset (&wi, 0, sizeof (wi));
1070 info.modified = false;
1071 wi.info = &info;
1072 walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
1073
1074 if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
1075 {
1076 tree retval = gimple_return_retval (return_stmt);
1077 edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
1078 e->flags |= EDGE_FALLTHRU;
1079 if (!retval)
1080 {
1081 gsi_remove (&gsi, true);
1082 continue;
1083 }
1084
1085 /* Replace `return foo' with `retval_array[iter] = foo'. */
1086 tree ref = build4 (ARRAY_REF, TREE_TYPE (retval),
1087 retval_array, iter, NULL, NULL);
1088 stmt = gimple_build_assign (ref, retval);
1089 gsi_replace (&gsi, stmt, true);
1090 info.modified = true;
1091 }
1092
1093 if (info.modified)
1094 {
1095 update_stmt (stmt);
1096 /* If the above changed the var of a debug bind into something
1097 different, remove the debug stmt. We could also for all the
1098 replaced parameters add VAR_DECLs for debug info purposes,
1099 add debug stmts for those to be the simd array accesses and
1100 replace debug stmt var operand with that var. Debugging of
1101 vectorized loops doesn't work too well, so don't bother for
1102 now. */
1103 if ((gimple_debug_bind_p (stmt)
1104 && !DECL_P (gimple_debug_bind_get_var (stmt)))
1105 || (gimple_debug_source_bind_p (stmt)
1106 && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
1107 {
1108 gsi_remove (&gsi, true);
1109 continue;
1110 }
1111 if (maybe_clean_eh_stmt (stmt))
1112 gimple_purge_dead_eh_edges (gimple_bb (stmt));
1113 }
1114 gsi_next (&gsi);
1115 }
1116 }
1117 }
1118
1119 /* Helper function of simd_clone_adjust, return linear step addend
1120 of Ith argument. */
1121
1122 static tree
1123 simd_clone_linear_addend (struct cgraph_node *node, unsigned int i,
1124 tree addtype, basic_block entry_bb)
1125 {
1126 tree ptype = NULL_TREE;
1127 switch (node->simdclone->args[i].arg_type)
1128 {
1129 case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
1130 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
1131 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1132 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
1133 return build_int_cst (addtype, node->simdclone->args[i].linear_step);
1134 case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
1135 case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
1136 ptype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1137 break;
1138 case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1139 case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1140 ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg));
1141 break;
1142 default:
1143 gcc_unreachable ();
1144 }
1145
1146 unsigned int idx = node->simdclone->args[i].linear_step;
1147 tree arg = node->simdclone->args[idx].orig_arg;
1148 gcc_assert (is_gimple_reg_type (TREE_TYPE (arg)));
1149 gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1150 gimple *g;
1151 tree ret;
1152 if (is_gimple_reg (arg))
1153 ret = get_or_create_ssa_default_def (cfun, arg);
1154 else
1155 {
1156 g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
1157 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1158 ret = gimple_assign_lhs (g);
1159 }
1160 if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
1161 {
1162 g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))),
1163 build_simple_mem_ref (ret));
1164 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1165 ret = gimple_assign_lhs (g);
1166 }
1167 if (!useless_type_conversion_p (addtype, TREE_TYPE (ret)))
1168 {
1169 g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret);
1170 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1171 ret = gimple_assign_lhs (g);
1172 }
1173 if (POINTER_TYPE_P (ptype))
1174 {
1175 tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype));
1176 if (size && TREE_CODE (size) == INTEGER_CST)
1177 {
1178 g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR,
1179 ret, fold_convert (addtype, size));
1180 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1181 ret = gimple_assign_lhs (g);
1182 }
1183 }
1184 return ret;
1185 }
1186
1187 /* Adjust the argument types in NODE to their appropriate vector
1188 counterparts. */
1189
1190 static void
1191 simd_clone_adjust (struct cgraph_node *node)
1192 {
1193 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
1194
1195 TREE_TYPE (node->decl) = build_distinct_type_copy (TREE_TYPE (node->decl));
1196 targetm.simd_clone.adjust (node);
1197
1198 tree retval = simd_clone_adjust_return_type (node);
1199 ipa_param_body_adjustments *adjustments
1200 = simd_clone_adjust_argument_types (node);
1201 gcc_assert (adjustments);
1202
1203 push_gimplify_context ();
1204
1205 gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments);
1206
1207 /* Adjust all uses of vector arguments accordingly. Adjust all
1208 return values accordingly. */
1209 tree iter = create_tmp_var (unsigned_type_node, "iter");
1210 tree iter1 = make_ssa_name (iter);
1211 tree iter2 = NULL_TREE;
1212 ipa_simd_modify_function_body (node, adjustments, retval, iter1);
1213 delete adjustments;
1214
1215 /* Initialize the iteration variable. */
1216 basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1217 basic_block body_bb = split_block_after_labels (entry_bb)->dest;
1218 gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1219 /* Insert the SIMD array and iv initialization at function
1220 entry. */
1221 gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
1222
1223 pop_gimplify_context (NULL);
1224
1225 gimple *g;
1226 basic_block incr_bb = NULL;
1227 class loop *loop = NULL;
1228
1229 /* Create a new BB right before the original exit BB, to hold the
1230 iteration increment and the condition/branch. */
1231 if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1232 {
1233 basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
1234 incr_bb = create_empty_bb (orig_exit);
1235 incr_bb->count = profile_count::zero ();
1236 add_bb_to_loop (incr_bb, body_bb->loop_father);
1237 while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1238 {
1239 edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1240 redirect_edge_succ (e, incr_bb);
1241 incr_bb->count += e->count ();
1242 }
1243 }
1244 else if (node->simdclone->inbranch)
1245 {
1246 incr_bb = create_empty_bb (entry_bb);
1247 incr_bb->count = profile_count::zero ();
1248 add_bb_to_loop (incr_bb, body_bb->loop_father);
1249 }
1250
1251 if (incr_bb)
1252 {
1253 make_single_succ_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1254 gsi = gsi_last_bb (incr_bb);
1255 iter2 = make_ssa_name (iter);
1256 g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
1257 build_int_cst (unsigned_type_node, 1));
1258 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1259
1260 /* Mostly annotate the loop for the vectorizer (the rest is done
1261 below). */
1262 loop = alloc_loop ();
1263 cfun->has_force_vectorize_loops = true;
1264 /* For now, simlen is always constant. */
1265 loop->safelen = node->simdclone->simdlen.to_constant ();
1266 loop->force_vectorize = true;
1267 loop->header = body_bb;
1268 }
1269
1270 /* Branch around the body if the mask applies. */
1271 if (node->simdclone->inbranch)
1272 {
1273 gsi = gsi_last_bb (loop->header);
1274 tree mask_array
1275 = node->simdclone->args[node->simdclone->nargs - 1].simd_array;
1276 tree mask;
1277 if (node->simdclone->mask_mode != VOIDmode)
1278 {
1279 tree shift_cnt;
1280 if (mask_array == NULL_TREE)
1281 {
1282 tree arg = node->simdclone->args[node->simdclone->nargs
1283 - 1].vector_arg;
1284 mask = get_or_create_ssa_default_def (cfun, arg);
1285 shift_cnt = iter1;
1286 }
1287 else
1288 {
1289 tree maskt = TREE_TYPE (mask_array);
1290 int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt)));
1291 /* For now, c must be constant here. */
1292 c = exact_div (node->simdclone->simdlen, c + 1).to_constant ();
1293 int s = exact_log2 (c);
1294 gcc_assert (s > 0);
1295 c--;
1296 tree idx = make_ssa_name (TREE_TYPE (iter1));
1297 g = gimple_build_assign (idx, RSHIFT_EXPR, iter1,
1298 build_int_cst (NULL_TREE, s));
1299 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1300 mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1301 tree aref = build4 (ARRAY_REF,
1302 TREE_TYPE (TREE_TYPE (mask_array)),
1303 mask_array, idx, NULL, NULL);
1304 g = gimple_build_assign (mask, aref);
1305 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1306 shift_cnt = make_ssa_name (TREE_TYPE (iter1));
1307 g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1,
1308 build_int_cst (TREE_TYPE (iter1), c));
1309 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1310 }
1311 g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1312 RSHIFT_EXPR, mask, shift_cnt);
1313 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1314 mask = gimple_assign_lhs (g);
1315 g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1316 BIT_AND_EXPR, mask,
1317 build_int_cst (TREE_TYPE (mask), 1));
1318 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1319 mask = gimple_assign_lhs (g);
1320 }
1321 else
1322 {
1323 mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1324 tree aref = build4 (ARRAY_REF,
1325 TREE_TYPE (TREE_TYPE (mask_array)),
1326 mask_array, iter1, NULL, NULL);
1327 g = gimple_build_assign (mask, aref);
1328 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1329 int bitsize = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (aref)));
1330 if (!INTEGRAL_TYPE_P (TREE_TYPE (aref)))
1331 {
1332 aref = build1 (VIEW_CONVERT_EXPR,
1333 build_nonstandard_integer_type (bitsize, 0),
1334 mask);
1335 mask = make_ssa_name (TREE_TYPE (aref));
1336 g = gimple_build_assign (mask, aref);
1337 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1338 }
1339 }
1340
1341 g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)),
1342 NULL, NULL);
1343 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1344 edge e = make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE);
1345 e->probability = profile_probability::unlikely ().guessed ();
1346 incr_bb->count += e->count ();
1347 edge fallthru = FALLTHRU_EDGE (loop->header);
1348 fallthru->flags = EDGE_FALSE_VALUE;
1349 fallthru->probability = profile_probability::likely ().guessed ();
1350 }
1351
1352 basic_block latch_bb = NULL;
1353 basic_block new_exit_bb = NULL;
1354
1355 /* Generate the condition. */
1356 if (incr_bb)
1357 {
1358 gsi = gsi_last_bb (incr_bb);
1359 g = gimple_build_cond (LT_EXPR, iter2,
1360 build_int_cst (unsigned_type_node,
1361 node->simdclone->simdlen),
1362 NULL, NULL);
1363 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1364 edge e = split_block (incr_bb, gsi_stmt (gsi));
1365 latch_bb = e->dest;
1366 new_exit_bb = split_block_after_labels (latch_bb)->dest;
1367 loop->latch = latch_bb;
1368
1369 redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
1370
1371 edge new_e = make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
1372
1373 /* FIXME: Do we need to distribute probabilities for the conditional? */
1374 new_e->probability = profile_probability::guessed_never ();
1375 /* The successor of incr_bb is already pointing to latch_bb; just
1376 change the flags.
1377 make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE); */
1378 FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
1379 }
1380
1381 gphi *phi = create_phi_node (iter1, body_bb);
1382 edge preheader_edge = find_edge (entry_bb, body_bb);
1383 edge latch_edge = NULL;
1384 add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
1385 UNKNOWN_LOCATION);
1386 if (incr_bb)
1387 {
1388 latch_edge = single_succ_edge (latch_bb);
1389 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1390
1391 /* Generate the new return. */
1392 gsi = gsi_last_bb (new_exit_bb);
1393 if (retval
1394 && TREE_CODE (retval) == VIEW_CONVERT_EXPR
1395 && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
1396 retval = TREE_OPERAND (retval, 0);
1397 else if (retval)
1398 {
1399 retval = build1 (VIEW_CONVERT_EXPR,
1400 TREE_TYPE (TREE_TYPE (node->decl)),
1401 retval);
1402 retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
1403 false, GSI_CONTINUE_LINKING);
1404 }
1405 g = gimple_build_return (retval);
1406 gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1407 }
1408
1409 /* Handle aligned clauses by replacing default defs of the aligned
1410 uniform args with __builtin_assume_aligned (arg_N(D), alignment)
1411 lhs. Handle linear by adding PHIs. */
1412 for (unsigned i = 0; i < node->simdclone->nargs; i++)
1413 if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1414 && (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg)
1415 || !is_gimple_reg_type
1416 (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1417 {
1418 tree orig_arg = node->simdclone->args[i].orig_arg;
1419 if (is_gimple_reg_type (TREE_TYPE (orig_arg)))
1420 iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1421 else
1422 {
1423 iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg));
1424 gimple_add_tmp_var (iter1);
1425 }
1426 gsi = gsi_after_labels (entry_bb);
1427 g = gimple_build_assign (iter1, orig_arg);
1428 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1429 gsi = gsi_after_labels (body_bb);
1430 g = gimple_build_assign (orig_arg, iter1);
1431 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1432 }
1433 else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1434 && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg)
1435 && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1436 == REFERENCE_TYPE
1437 && TREE_ADDRESSABLE
1438 (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1439 {
1440 tree orig_arg = node->simdclone->args[i].orig_arg;
1441 tree def = ssa_default_def (cfun, orig_arg);
1442 if (def && !has_zero_uses (def))
1443 {
1444 iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg)));
1445 gimple_add_tmp_var (iter1);
1446 gsi = gsi_after_labels (entry_bb);
1447 g = gimple_build_assign (iter1, build_simple_mem_ref (def));
1448 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1449 gsi = gsi_after_labels (body_bb);
1450 g = gimple_build_assign (build_simple_mem_ref (def), iter1);
1451 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1452 }
1453 }
1454 else if (node->simdclone->args[i].alignment
1455 && node->simdclone->args[i].arg_type
1456 == SIMD_CLONE_ARG_TYPE_UNIFORM
1457 && (node->simdclone->args[i].alignment
1458 & (node->simdclone->args[i].alignment - 1)) == 0
1459 && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1460 == POINTER_TYPE)
1461 {
1462 unsigned int alignment = node->simdclone->args[i].alignment;
1463 tree orig_arg = node->simdclone->args[i].orig_arg;
1464 tree def = ssa_default_def (cfun, orig_arg);
1465 if (def && !has_zero_uses (def))
1466 {
1467 tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
1468 gimple_seq seq = NULL;
1469 bool need_cvt = false;
1470 gcall *call
1471 = gimple_build_call (fn, 2, def, size_int (alignment));
1472 g = call;
1473 if (!useless_type_conversion_p (TREE_TYPE (orig_arg),
1474 ptr_type_node))
1475 need_cvt = true;
1476 tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg);
1477 gimple_call_set_lhs (g, t);
1478 gimple_seq_add_stmt_without_update (&seq, g);
1479 if (need_cvt)
1480 {
1481 t = make_ssa_name (orig_arg);
1482 g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g));
1483 gimple_seq_add_stmt_without_update (&seq, g);
1484 }
1485 gsi_insert_seq_on_edge_immediate
1486 (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
1487
1488 entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1489 node->create_edge (cgraph_node::get_create (fn),
1490 call, entry_bb->count);
1491
1492 imm_use_iterator iter;
1493 use_operand_p use_p;
1494 gimple *use_stmt;
1495 tree repl = gimple_get_lhs (g);
1496 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1497 if (is_gimple_debug (use_stmt) || use_stmt == call)
1498 continue;
1499 else
1500 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1501 SET_USE (use_p, repl);
1502 }
1503 }
1504 else if ((node->simdclone->args[i].arg_type
1505 == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
1506 || (node->simdclone->args[i].arg_type
1507 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
1508 || (node->simdclone->args[i].arg_type
1509 == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP)
1510 || (node->simdclone->args[i].arg_type
1511 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP))
1512 {
1513 tree orig_arg = node->simdclone->args[i].orig_arg;
1514 gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1515 || POINTER_TYPE_P (TREE_TYPE (orig_arg)));
1516 tree def = NULL_TREE;
1517 if (TREE_ADDRESSABLE (orig_arg))
1518 {
1519 def = make_ssa_name (TREE_TYPE (orig_arg));
1520 iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1521 if (incr_bb)
1522 iter2 = make_ssa_name (TREE_TYPE (orig_arg));
1523 gsi = gsi_after_labels (entry_bb);
1524 g = gimple_build_assign (def, orig_arg);
1525 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1526 }
1527 else
1528 {
1529 def = ssa_default_def (cfun, orig_arg);
1530 if (!def || has_zero_uses (def))
1531 def = NULL_TREE;
1532 else
1533 {
1534 iter1 = make_ssa_name (orig_arg);
1535 if (incr_bb)
1536 iter2 = make_ssa_name (orig_arg);
1537 }
1538 }
1539 if (def)
1540 {
1541 phi = create_phi_node (iter1, body_bb);
1542 add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
1543 if (incr_bb)
1544 {
1545 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1546 enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1547 ? PLUS_EXPR : POINTER_PLUS_EXPR;
1548 tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1549 ? TREE_TYPE (orig_arg) : sizetype;
1550 tree addcst = simd_clone_linear_addend (node, i, addtype,
1551 entry_bb);
1552 gsi = gsi_last_bb (incr_bb);
1553 g = gimple_build_assign (iter2, code, iter1, addcst);
1554 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1555 }
1556
1557 imm_use_iterator iter;
1558 use_operand_p use_p;
1559 gimple *use_stmt;
1560 if (TREE_ADDRESSABLE (orig_arg))
1561 {
1562 gsi = gsi_after_labels (body_bb);
1563 g = gimple_build_assign (orig_arg, iter1);
1564 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1565 }
1566 else
1567 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1568 if (use_stmt == phi)
1569 continue;
1570 else
1571 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1572 SET_USE (use_p, iter1);
1573 }
1574 }
1575 else if (node->simdclone->args[i].arg_type
1576 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP
1577 || (node->simdclone->args[i].arg_type
1578 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP))
1579 {
1580 tree orig_arg = node->simdclone->args[i].orig_arg;
1581 tree def = ssa_default_def (cfun, orig_arg);
1582 gcc_assert (!TREE_ADDRESSABLE (orig_arg)
1583 && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE);
1584 if (def && !has_zero_uses (def))
1585 {
1586 tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
1587 iter1 = make_ssa_name (orig_arg);
1588 if (incr_bb)
1589 iter2 = make_ssa_name (orig_arg);
1590 tree iter3 = make_ssa_name (rtype);
1591 tree iter4 = make_ssa_name (rtype);
1592 tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
1593 gsi = gsi_after_labels (entry_bb);
1594 gimple *load
1595 = gimple_build_assign (iter3, build_simple_mem_ref (def));
1596 gsi_insert_before (&gsi, load, GSI_NEW_STMT);
1597
1598 tree array = node->simdclone->args[i].simd_array;
1599 TREE_ADDRESSABLE (array) = 1;
1600 tree ptr = build_fold_addr_expr (array);
1601 phi = create_phi_node (iter1, body_bb);
1602 add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
1603 if (incr_bb)
1604 {
1605 add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1606 g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
1607 TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
1608 gsi = gsi_last_bb (incr_bb);
1609 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1610 }
1611
1612 phi = create_phi_node (iter4, body_bb);
1613 add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
1614 if (incr_bb)
1615 {
1616 add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
1617 enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1618 ? PLUS_EXPR : POINTER_PLUS_EXPR;
1619 tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1620 ? TREE_TYPE (iter3) : sizetype;
1621 tree addcst = simd_clone_linear_addend (node, i, addtype,
1622 entry_bb);
1623 g = gimple_build_assign (iter5, code, iter4, addcst);
1624 gsi = gsi_last_bb (incr_bb);
1625 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1626 }
1627
1628 g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
1629 gsi = gsi_after_labels (body_bb);
1630 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1631
1632 imm_use_iterator iter;
1633 use_operand_p use_p;
1634 gimple *use_stmt;
1635 FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1636 if (use_stmt == load)
1637 continue;
1638 else
1639 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1640 SET_USE (use_p, iter1);
1641
1642 if (!TYPE_READONLY (rtype) && incr_bb)
1643 {
1644 tree v = make_ssa_name (rtype);
1645 tree aref = build4 (ARRAY_REF, rtype, array,
1646 size_zero_node, NULL_TREE,
1647 NULL_TREE);
1648 gsi = gsi_after_labels (new_exit_bb);
1649 g = gimple_build_assign (v, aref);
1650 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1651 g = gimple_build_assign (build_simple_mem_ref (def), v);
1652 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1653 }
1654 }
1655 }
1656
1657 calculate_dominance_info (CDI_DOMINATORS);
1658 if (loop)
1659 add_loop (loop, loop->header->loop_father);
1660 update_ssa (TODO_update_ssa);
1661
1662 pop_cfun ();
1663 }
1664
1665 /* If the function in NODE is tagged as an elemental SIMD function,
1666 create the appropriate SIMD clones. */
1667
1668 void
1669 expand_simd_clones (struct cgraph_node *node)
1670 {
1671 tree attr = lookup_attribute ("omp declare simd",
1672 DECL_ATTRIBUTES (node->decl));
1673 if (attr == NULL_TREE
1674 || node->inlined_to
1675 || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
1676 return;
1677
1678 /* Ignore
1679 #pragma omp declare simd
1680 extern int foo ();
1681 in C, there we don't know the argument types at all. */
1682 if (!node->definition
1683 && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE)
1684 return;
1685
1686 /* Call this before creating clone_info, as it might ggc_collect. */
1687 if (node->definition && node->has_gimple_body_p ())
1688 node->get_body ();
1689
1690 do
1691 {
1692 /* Start with parsing the "omp declare simd" attribute(s). */
1693 bool inbranch_clause_specified;
1694 struct cgraph_simd_clone *clone_info
1695 = simd_clone_clauses_extract (node, TREE_VALUE (attr),
1696 &inbranch_clause_specified);
1697 if (clone_info == NULL)
1698 continue;
1699
1700 poly_uint64 orig_simdlen = clone_info->simdlen;
1701 tree base_type = simd_clone_compute_base_data_type (node, clone_info);
1702 /* The target can return 0 (no simd clones should be created),
1703 1 (just one ISA of simd clones should be created) or higher
1704 count of ISA variants. In that case, clone_info is initialized
1705 for the first ISA variant. */
1706 int count
1707 = targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info,
1708 base_type, 0);
1709 if (count == 0)
1710 continue;
1711
1712 /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED,
1713 also create one inbranch and one !inbranch clone of it. */
1714 for (int i = 0; i < count * 2; i++)
1715 {
1716 struct cgraph_simd_clone *clone = clone_info;
1717 if (inbranch_clause_specified && (i & 1) != 0)
1718 continue;
1719
1720 if (i != 0)
1721 {
1722 clone = simd_clone_struct_alloc (clone_info->nargs
1723 + ((i & 1) != 0));
1724 simd_clone_struct_copy (clone, clone_info);
1725 /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen
1726 and simd_clone_adjust_argument_types did to the first
1727 clone's info. */
1728 clone->nargs -= clone_info->inbranch;
1729 clone->simdlen = orig_simdlen;
1730 /* And call the target hook again to get the right ISA. */
1731 targetm.simd_clone.compute_vecsize_and_simdlen (node, clone,
1732 base_type,
1733 i / 2);
1734 if ((i & 1) != 0)
1735 clone->inbranch = 1;
1736 }
1737
1738 /* simd_clone_mangle might fail if such a clone has been created
1739 already. */
1740 tree id = simd_clone_mangle (node, clone);
1741 if (id == NULL_TREE)
1742 {
1743 if (i == 0)
1744 clone->nargs += clone->inbranch;
1745 continue;
1746 }
1747
1748 /* Only when we are sure we want to create the clone actually
1749 clone the function (or definitions) or create another
1750 extern FUNCTION_DECL (for prototypes without definitions). */
1751 struct cgraph_node *n = simd_clone_create (node);
1752 if (n == NULL)
1753 {
1754 if (i == 0)
1755 clone->nargs += clone->inbranch;
1756 continue;
1757 }
1758
1759 n->simdclone = clone;
1760 clone->origin = node;
1761 clone->next_clone = NULL;
1762 if (node->simd_clones == NULL)
1763 {
1764 clone->prev_clone = n;
1765 node->simd_clones = n;
1766 }
1767 else
1768 {
1769 clone->prev_clone = node->simd_clones->simdclone->prev_clone;
1770 clone->prev_clone->simdclone->next_clone = n;
1771 node->simd_clones->simdclone->prev_clone = n;
1772 }
1773 symtab->change_decl_assembler_name (n->decl, id);
1774 /* And finally adjust the return type, parameters and for
1775 definitions also function body. */
1776 if (node->definition)
1777 simd_clone_adjust (n);
1778 else
1779 {
1780 TREE_TYPE (n->decl)
1781 = build_distinct_type_copy (TREE_TYPE (n->decl));
1782 targetm.simd_clone.adjust (n);
1783 simd_clone_adjust_return_type (n);
1784 simd_clone_adjust_argument_types (n);
1785 }
1786 }
1787 }
1788 while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
1789 }
1790
1791 /* Entry point for IPA simd clone creation pass. */
1792
1793 static unsigned int
1794 ipa_omp_simd_clone (void)
1795 {
1796 struct cgraph_node *node;
1797 FOR_EACH_FUNCTION (node)
1798 expand_simd_clones (node);
1799 return 0;
1800 }
1801
1802 namespace {
1803
1804 const pass_data pass_data_omp_simd_clone =
1805 {
1806 SIMPLE_IPA_PASS, /* type */
1807 "simdclone", /* name */
1808 OPTGROUP_OMP, /* optinfo_flags */
1809 TV_NONE, /* tv_id */
1810 ( PROP_ssa | PROP_cfg ), /* properties_required */
1811 0, /* properties_provided */
1812 0, /* properties_destroyed */
1813 0, /* todo_flags_start */
1814 0, /* todo_flags_finish */
1815 };
1816
1817 class pass_omp_simd_clone : public simple_ipa_opt_pass
1818 {
1819 public:
1820 pass_omp_simd_clone(gcc::context *ctxt)
1821 : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt)
1822 {}
1823
1824 /* opt_pass methods: */
1825 virtual bool gate (function *);
1826 virtual unsigned int execute (function *) { return ipa_omp_simd_clone (); }
1827 };
1828
1829 bool
1830 pass_omp_simd_clone::gate (function *)
1831 {
1832 return targetm.simd_clone.compute_vecsize_and_simdlen != NULL;
1833 }
1834
1835 } // anon namespace
1836
1837 simple_ipa_opt_pass *
1838 make_pass_omp_simd_clone (gcc::context *ctxt)
1839 {
1840 return new pass_omp_simd_clone (ctxt);
1841 }