Branch data Line data Source code
1 : : /* OMP constructs' SIMD clone supporting code.
2 : :
3 : : Copyright (C) 2005-2024 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 : : #include "omp-low.h"
55 : : #include "omp-general.h"
56 : :
57 : : /* Print debug info for ok_for_auto_simd_clone to the dump file, logging
58 : : failure reason EXCUSE for function DECL. Always returns false. */
59 : : static bool
60 : 79 : auto_simd_fail (tree decl, const char *excuse)
61 : : {
62 : 79 : if (dump_file && (dump_flags & TDF_DETAILS))
63 : 158 : fprintf (dump_file, "\nNot auto-cloning %s because %s\n",
64 : 79 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
65 : : excuse);
66 : 79 : return false;
67 : : }
68 : :
69 : : /* Helper function for ok_for_auto_simd_clone; return false if the statement
70 : : violates restrictions for an "omp declare simd" function. Specifically,
71 : : the function must not
72 : : - throw or call setjmp/longjmp
73 : : - write memory that could alias parallel calls
74 : : - read volatile memory
75 : : - include openmp directives or calls
76 : : - call functions that might do those things */
77 : :
78 : : static bool
79 : 21 : auto_simd_check_stmt (gimple *stmt, tree outer)
80 : : {
81 : 21 : tree decl;
82 : :
83 : 21 : switch (gimple_code (stmt))
84 : : {
85 : 5 : case GIMPLE_CALL:
86 : :
87 : : /* Calls to functions that are CONST or PURE are ok, even if they
88 : : are internal functions without a decl. Reject other internal
89 : : functions. */
90 : 5 : if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))
91 : : break;
92 : 5 : if (gimple_call_internal_p (stmt))
93 : 0 : return auto_simd_fail (outer,
94 : 0 : "body contains internal function call");
95 : :
96 : 5 : decl = gimple_call_fndecl (stmt);
97 : :
98 : : /* We can't know whether indirect calls are safe. */
99 : 5 : if (decl == NULL_TREE)
100 : 0 : return auto_simd_fail (outer, "body contains indirect call");
101 : :
102 : : /* Calls to functions that are already marked "omp declare simd" are
103 : : OK. */
104 : 5 : if (lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (decl)))
105 : : break;
106 : :
107 : : /* Let recursive calls to the current function through. */
108 : 5 : if (decl == outer)
109 : : break;
110 : :
111 : : /* Other function calls are not permitted. This covers all calls to
112 : : the libgomp API and setjmp/longjmp, too, as well as things like
113 : : __cxa_throw_ related to exception handling. */
114 : 5 : return auto_simd_fail (outer, "body contains unsafe function call");
115 : :
116 : : /* Reject EH-related constructs. Most of the EH gimple codes are
117 : : already lowered by the time this pass runs during IPA.
118 : : GIMPLE_EH_DISPATCH and GIMPLE_RESX remain and are lowered by
119 : : pass_lower_eh_dispatch and pass_lower_resx, respectively; those
120 : : passes run later. */
121 : 0 : case GIMPLE_EH_DISPATCH:
122 : 0 : case GIMPLE_RESX:
123 : 0 : return auto_simd_fail (outer, "body contains EH constructs");
124 : :
125 : : /* Asms are not permitted since we don't know what they do. */
126 : 0 : case GIMPLE_ASM:
127 : 0 : return auto_simd_fail (outer, "body contains inline asm");
128 : :
129 : : default:
130 : : break;
131 : : }
132 : :
133 : : /* Memory writes are not permitted.
134 : : FIXME: this could be relaxed a little to permit writes to
135 : : function-local variables that could not alias other instances
136 : : of the function running in parallel. */
137 : 16 : if (gimple_store_p (stmt))
138 : 1 : return auto_simd_fail (outer, "body includes memory write");
139 : :
140 : : /* Volatile reads are not permitted. */
141 : 26 : if (gimple_has_volatile_ops (stmt))
142 : 1 : return auto_simd_fail (outer, "body includes volatile op");
143 : :
144 : : /* Otherwise OK. */
145 : : return true;
146 : : }
147 : :
148 : : /* Helper function for ok_for_auto_simd_clone: return true if type T is
149 : : plausible for a cloneable function argument or return type. */
150 : : static bool
151 : 50 : plausible_type_for_simd_clone (tree t)
152 : : {
153 : 50 : if (VOID_TYPE_P (t))
154 : : return true;
155 : 38 : else if (RECORD_OR_UNION_TYPE_P (t) || !is_a <scalar_mode> (TYPE_MODE (t)))
156 : : /* Small record/union types may fit into a scalar mode, but are
157 : : still not suitable. */
158 : 1 : return false;
159 : 37 : else if (TYPE_ATOMIC (t))
160 : : /* Atomic types trigger warnings in simd_clone_clauses_extract. */
161 : : return false;
162 : : else
163 : : return true;
164 : : }
165 : :
166 : : /* Check if the function NODE appears suitable for auto-annotation
167 : : with "declare simd". */
168 : :
169 : : static bool
170 : 84 : ok_for_auto_simd_clone (struct cgraph_node *node)
171 : : {
172 : 84 : tree decl = node->decl;
173 : 84 : tree t;
174 : 84 : basic_block bb;
175 : :
176 : : /* Nothing to do if the function isn't a definition or doesn't
177 : : have a body. */
178 : 84 : if (!node->definition || !node->has_gimple_body_p ())
179 : 55 : return auto_simd_fail (decl, "no definition or body");
180 : :
181 : : /* No point in trying to generate implicit clones if the function
182 : : isn't used in the compilation unit. */
183 : 29 : if (!node->callers)
184 : 15 : return auto_simd_fail (decl, "function is not used");
185 : :
186 : : /* Nothing to do if the function already has the "omp declare simd"
187 : : attribute, is marked noclone, or is not "omp declare target". */
188 : 14 : if (lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (decl))
189 : 14 : || lookup_attribute ("noclone", DECL_ATTRIBUTES (decl))
190 : 28 : || !lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)))
191 : 0 : return auto_simd_fail (decl, "incompatible attributes");
192 : :
193 : : /* Check whether the function is restricted host/nohost via the
194 : : "omp declare target device_type" clause, and that doesn't match
195 : : what we're compiling for. Internally, these translate into
196 : : "omp declare target [no]host" attributes on the decl; "any"
197 : : translates into both attributes, but the default (which is supposed
198 : : to be equivalent to "any") is neither. */
199 : 14 : tree host = lookup_attribute ("omp declare target host",
200 : 14 : DECL_ATTRIBUTES (decl));
201 : 14 : tree nohost = lookup_attribute ("omp declare target nohost",
202 : 14 : DECL_ATTRIBUTES (decl));
203 : : #ifdef ACCEL_COMPILER
204 : : if (host && !nohost)
205 : : return auto_simd_fail (decl, "device doesn't match for accel compiler");
206 : : #else
207 : 14 : if (nohost && !host)
208 : 1 : return auto_simd_fail (decl, "device doesn't match for host compiler");
209 : : #endif
210 : :
211 : : /* Backends will check for vectorizable arguments/return types in a
212 : : target-specific way, but we can immediately filter out functions
213 : : that have implausible argument/return types. */
214 : 13 : t = TREE_TYPE (TREE_TYPE (decl));
215 : 13 : if (!plausible_type_for_simd_clone (t))
216 : 0 : return auto_simd_fail (decl, "return type fails sniff test");
217 : :
218 : 13 : if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
219 : : {
220 : 13 : for (tree temp = TYPE_ARG_TYPES (TREE_TYPE (decl));
221 : 49 : temp; temp = TREE_CHAIN (temp))
222 : : {
223 : 37 : t = TREE_VALUE (temp);
224 : 37 : if (!plausible_type_for_simd_clone (t))
225 : 1 : return auto_simd_fail (decl, "argument type fails sniff test");
226 : : }
227 : : }
228 : 0 : else if (DECL_ARGUMENTS (decl))
229 : : {
230 : 0 : for (tree temp = DECL_ARGUMENTS (decl); temp; temp = DECL_CHAIN (temp))
231 : : {
232 : 0 : t = TREE_TYPE (temp);
233 : 0 : if (!plausible_type_for_simd_clone (t))
234 : 0 : return auto_simd_fail (decl, "argument type fails sniff test");
235 : : }
236 : : }
237 : : else
238 : 0 : return auto_simd_fail (decl, "function has no arguments");
239 : :
240 : : /* Scan the function body to see if it is suitable for SIMD-ization. */
241 : 12 : node->get_body ();
242 : :
243 : 21 : FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (decl))
244 : : {
245 : 46 : for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
246 : 14 : gsi_next (&gsi))
247 : 21 : if (!auto_simd_check_stmt (gsi_stmt (gsi), decl))
248 : 84 : return false;
249 : : }
250 : :
251 : : /* All is good. */
252 : 5 : if (dump_file)
253 : 10 : fprintf (dump_file, "\nMarking %s for auto-cloning\n",
254 : 5 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
255 : : return true;
256 : : }
257 : :
258 : : /* Allocate a fresh `simd_clone' and return it. NARGS is the number
259 : : of arguments to reserve space for. */
260 : :
261 : : static struct cgraph_simd_clone *
262 : 8078 : simd_clone_struct_alloc (int nargs)
263 : : {
264 : 8078 : struct cgraph_simd_clone *clone_info;
265 : 8078 : size_t len = (sizeof (struct cgraph_simd_clone)
266 : 8078 : + nargs * sizeof (struct cgraph_simd_clone_arg));
267 : 8078 : clone_info = (struct cgraph_simd_clone *)
268 : 8078 : ggc_internal_cleared_alloc (len);
269 : 8078 : return clone_info;
270 : : }
271 : :
272 : : /* Make a copy of the `struct cgraph_simd_clone' in FROM to TO. */
273 : :
274 : : static inline void
275 : 6512 : simd_clone_struct_copy (struct cgraph_simd_clone *to,
276 : : struct cgraph_simd_clone *from)
277 : : {
278 : 6512 : memcpy (to, from, (sizeof (struct cgraph_simd_clone)
279 : 6512 : + ((from->nargs - from->inbranch)
280 : 6512 : * sizeof (struct cgraph_simd_clone_arg))));
281 : 6512 : }
282 : :
283 : : /* Fill an empty vector ARGS with parameter types of function FNDECL. This
284 : : uses TYPE_ARG_TYPES if available, otherwise falls back to types of
285 : : DECL_ARGUMENTS types. */
286 : :
287 : : static void
288 : 4801 : simd_clone_vector_of_formal_parm_types (vec<tree> *args, tree fndecl)
289 : : {
290 : 4801 : if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
291 : : {
292 : 4763 : push_function_arg_types (args, TREE_TYPE (fndecl));
293 : 4763 : return;
294 : : }
295 : 38 : push_function_arg_decls (args, fndecl);
296 : 38 : unsigned int i;
297 : 38 : tree arg;
298 : 81 : FOR_EACH_VEC_ELT (*args, i, arg)
299 : 5 : (*args)[i] = TREE_TYPE ((*args)[i]);
300 : : }
301 : :
302 : : /* Given a simd function in NODE, extract the simd specific
303 : : information from the OMP clauses passed in CLAUSES, and return
304 : : the struct cgraph_simd_clone * if it should be cloned. *INBRANCH_SPECIFIED
305 : : is set to TRUE if the `inbranch' or `notinbranch' clause specified,
306 : : otherwise set to FALSE. */
307 : :
308 : : static struct cgraph_simd_clone *
309 : 1566 : simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
310 : : bool *inbranch_specified)
311 : : {
312 : 1566 : auto_vec<tree> args;
313 : 1566 : simd_clone_vector_of_formal_parm_types (&args, node->decl);
314 : 1566 : tree t;
315 : 1566 : int n;
316 : 1566 : *inbranch_specified = false;
317 : :
318 : 1566 : n = args.length ();
319 : 3120 : if (n > 0 && args.last () == void_type_node)
320 : 1558 : n--;
321 : :
322 : : /* Allocate one more than needed just in case this is an in-branch
323 : : clone which will require a mask argument. */
324 : 1566 : struct cgraph_simd_clone *clone_info = simd_clone_struct_alloc (n + 1);
325 : 1566 : clone_info->nargs = n;
326 : :
327 : 1566 : if (!clauses)
328 : 179 : goto out;
329 : :
330 : 1387 : clauses = TREE_VALUE (clauses);
331 : 1387 : if (!clauses || TREE_CODE (clauses) != OMP_CLAUSE)
332 : 99 : goto out;
333 : :
334 : 3649 : for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t))
335 : : {
336 : 2361 : switch (OMP_CLAUSE_CODE (t))
337 : : {
338 : 108 : case OMP_CLAUSE_INBRANCH:
339 : 108 : clone_info->inbranch = 1;
340 : 108 : *inbranch_specified = true;
341 : 108 : break;
342 : 902 : case OMP_CLAUSE_NOTINBRANCH:
343 : 902 : clone_info->inbranch = 0;
344 : 902 : *inbranch_specified = true;
345 : 902 : break;
346 : 251 : case OMP_CLAUSE_SIMDLEN:
347 : 251 : clone_info->simdlen
348 : 251 : = TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
349 : 251 : break;
350 : 572 : case OMP_CLAUSE_LINEAR:
351 : 572 : {
352 : 572 : tree decl = OMP_CLAUSE_DECL (t);
353 : 572 : tree step = OMP_CLAUSE_LINEAR_STEP (t);
354 : 572 : int argno = TREE_INT_CST_LOW (decl);
355 : 572 : if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (t))
356 : : {
357 : 39 : enum cgraph_simd_clone_arg_type arg_type;
358 : 39 : if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
359 : 14 : switch (OMP_CLAUSE_LINEAR_KIND (t))
360 : : {
361 : : case OMP_CLAUSE_LINEAR_REF:
362 : : arg_type
363 : : = SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP;
364 : : break;
365 : : case OMP_CLAUSE_LINEAR_UVAL:
366 : : arg_type
367 : : = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP;
368 : : break;
369 : : case OMP_CLAUSE_LINEAR_VAL:
370 : : case OMP_CLAUSE_LINEAR_DEFAULT:
371 : : arg_type
372 : : = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP;
373 : : break;
374 : 0 : default:
375 : 0 : gcc_unreachable ();
376 : : }
377 : : else
378 : : arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP;
379 : 39 : clone_info->args[argno].arg_type = arg_type;
380 : 39 : clone_info->args[argno].linear_step = tree_to_shwi (step);
381 : 39 : gcc_assert (clone_info->args[argno].linear_step >= 0
382 : : && clone_info->args[argno].linear_step < n);
383 : : }
384 : : else
385 : : {
386 : 533 : if (POINTER_TYPE_P (args[argno]))
387 : 217 : step = fold_convert (ssizetype, step);
388 : 533 : if (!tree_fits_shwi_p (step))
389 : : {
390 : 0 : warning_at (OMP_CLAUSE_LOCATION (t), OPT_Wopenmp,
391 : : "ignoring large linear step");
392 : 0 : return NULL;
393 : : }
394 : 533 : else if (integer_zerop (step))
395 : : {
396 : 0 : warning_at (OMP_CLAUSE_LOCATION (t), OPT_Wopenmp,
397 : : "ignoring zero linear step");
398 : 0 : return NULL;
399 : : }
400 : : else
401 : : {
402 : 533 : enum cgraph_simd_clone_arg_type arg_type;
403 : 533 : if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
404 : 140 : switch (OMP_CLAUSE_LINEAR_KIND (t))
405 : : {
406 : : case OMP_CLAUSE_LINEAR_REF:
407 : : arg_type
408 : : = SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP;
409 : : break;
410 : : case OMP_CLAUSE_LINEAR_UVAL:
411 : : arg_type
412 : : = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP;
413 : : break;
414 : : case OMP_CLAUSE_LINEAR_VAL:
415 : : case OMP_CLAUSE_LINEAR_DEFAULT:
416 : : arg_type
417 : : = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP;
418 : : break;
419 : 0 : default:
420 : 0 : gcc_unreachable ();
421 : : }
422 : : else
423 : : arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP;
424 : 533 : clone_info->args[argno].arg_type = arg_type;
425 : 533 : clone_info->args[argno].linear_step = tree_to_shwi (step);
426 : : }
427 : : }
428 : : break;
429 : : }
430 : 424 : case OMP_CLAUSE_UNIFORM:
431 : 424 : {
432 : 424 : tree decl = OMP_CLAUSE_DECL (t);
433 : 424 : int argno = tree_to_uhwi (decl);
434 : 424 : clone_info->args[argno].arg_type
435 : 424 : = SIMD_CLONE_ARG_TYPE_UNIFORM;
436 : 424 : break;
437 : : }
438 : 104 : case OMP_CLAUSE_ALIGNED:
439 : 104 : {
440 : : /* Ignore aligned (x) for declare simd, for the ABI we really
441 : : need an alignment specified. */
442 : 104 : if (OMP_CLAUSE_ALIGNED_ALIGNMENT (t) == NULL_TREE)
443 : : break;
444 : 99 : tree decl = OMP_CLAUSE_DECL (t);
445 : 99 : int argno = tree_to_uhwi (decl);
446 : 99 : clone_info->args[argno].alignment
447 : 99 : = TREE_INT_CST_LOW (OMP_CLAUSE_ALIGNED_ALIGNMENT (t));
448 : 99 : break;
449 : : }
450 : : default:
451 : : break;
452 : : }
453 : : }
454 : :
455 : 1288 : out:
456 : 1566 : if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (node->decl))))
457 : : {
458 : 0 : warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wopenmp,
459 : : "ignoring %<#pragma omp declare simd%> on function "
460 : : "with %<_Atomic%> qualified return type");
461 : 0 : return NULL;
462 : : }
463 : :
464 : 4295 : for (unsigned int argno = 0; argno < clone_info->nargs; argno++)
465 : 2730 : if (TYPE_ATOMIC (args[argno])
466 : 2730 : && clone_info->args[argno].arg_type != SIMD_CLONE_ARG_TYPE_UNIFORM)
467 : : {
468 : 1 : warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wopenmp,
469 : : "ignoring %<#pragma omp declare simd%> on function "
470 : : "with %<_Atomic%> qualified non-%<uniform%> argument");
471 : 1 : args.release ();
472 : 1 : return NULL;
473 : : }
474 : :
475 : : return clone_info;
476 : 1566 : }
477 : :
478 : : /* Given a SIMD clone in NODE, calculate the characteristic data
479 : : type and return the coresponding type. The characteristic data
480 : : type is computed as described in the Intel Vector ABI. */
481 : :
482 : : static tree
483 : 3878 : simd_clone_compute_base_data_type (struct cgraph_node *node,
484 : : struct cgraph_simd_clone *clone_info)
485 : : {
486 : 3878 : tree type = integer_type_node;
487 : 3878 : tree fndecl = node->decl;
488 : :
489 : : /* a) For non-void function, the characteristic data type is the
490 : : return type. */
491 : 3878 : if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE)
492 : 3411 : type = TREE_TYPE (TREE_TYPE (fndecl));
493 : :
494 : : /* b) If the function has any non-uniform, non-linear parameters,
495 : : then the characteristic data type is the type of the first
496 : : such parameter. */
497 : : else
498 : : {
499 : 467 : auto_vec<tree> map;
500 : 467 : simd_clone_vector_of_formal_parm_types (&map, fndecl);
501 : 581 : for (unsigned int i = 0; i < clone_info->nargs; ++i)
502 : 249 : if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
503 : : {
504 : 135 : type = map[i];
505 : 135 : break;
506 : : }
507 : 467 : }
508 : :
509 : : /* c) If the characteristic data type determined by a) or b) above
510 : : is struct, union, or class type which is pass-by-value (except
511 : : for the type that maps to the built-in complex data type), the
512 : : characteristic data type is int. */
513 : 3878 : if (RECORD_OR_UNION_TYPE_P (type)
514 : 2 : && !aggregate_value_p (type, NULL)
515 : 3880 : && TREE_CODE (type) != COMPLEX_TYPE)
516 : 2 : return integer_type_node;
517 : :
518 : : /* d) If none of the above three classes is applicable, the
519 : : characteristic data type is int. */
520 : :
521 : : return type;
522 : :
523 : : /* e) For Intel Xeon Phi native and offload compilation, if the
524 : : resulting characteristic data type is 8-bit or 16-bit integer
525 : : data type, the characteristic data type is int. */
526 : : /* Well, we don't handle Xeon Phi yet. */
527 : : }
528 : :
529 : : static tree
530 : 8070 : simd_clone_mangle (struct cgraph_node *node,
531 : : struct cgraph_simd_clone *clone_info)
532 : : {
533 : 8070 : char vecsize_mangle = clone_info->vecsize_mangle;
534 : 8070 : char mask = clone_info->inbranch ? 'M' : 'N';
535 : 8070 : poly_uint64 simdlen = clone_info->simdlen;
536 : 8070 : unsigned int n;
537 : 8070 : pretty_printer pp;
538 : :
539 : 8070 : gcc_assert (vecsize_mangle && maybe_ne (simdlen, 0U));
540 : :
541 : 8070 : pp_string (&pp, "_ZGV");
542 : 8070 : pp_character (&pp, vecsize_mangle);
543 : 8070 : pp_character (&pp, mask);
544 : : /* For now, simdlen is always constant, while variable simdlen pp 'n'. */
545 : 8070 : unsigned int len = simdlen.to_constant ();
546 : 8070 : pp_decimal_int (&pp, (len));
547 : :
548 : 22075 : for (n = 0; n < clone_info->nargs; ++n)
549 : : {
550 : 14005 : struct cgraph_simd_clone_arg arg = clone_info->args[n];
551 : :
552 : 14005 : switch (arg.arg_type)
553 : : {
554 : 2361 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
555 : 2361 : pp_character (&pp, 'u');
556 : 2361 : break;
557 : 2201 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
558 : 2201 : pp_character (&pp, 'l');
559 : 2201 : goto mangle_linear;
560 : 404 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
561 : 404 : pp_character (&pp, 'R');
562 : 404 : goto mangle_linear;
563 : 208 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
564 : 208 : pp_character (&pp, 'L');
565 : 208 : goto mangle_linear;
566 : 208 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
567 : 208 : pp_character (&pp, 'U');
568 : 208 : goto mangle_linear;
569 : 3021 : mangle_linear:
570 : 3021 : gcc_assert (arg.linear_step != 0);
571 : 3021 : if (arg.linear_step > 1)
572 : 1410 : pp_unsigned_wide_integer (&pp, arg.linear_step);
573 : 1611 : else if (arg.linear_step < 0)
574 : : {
575 : 89 : pp_character (&pp, 'n');
576 : 89 : pp_unsigned_wide_integer (&pp, (-(unsigned HOST_WIDE_INT)
577 : : arg.linear_step));
578 : : }
579 : : break;
580 : 140 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
581 : 140 : pp_string (&pp, "ls");
582 : 140 : pp_unsigned_wide_integer (&pp, arg.linear_step);
583 : 140 : break;
584 : 32 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
585 : 32 : pp_string (&pp, "Rs");
586 : 32 : pp_unsigned_wide_integer (&pp, arg.linear_step);
587 : 32 : break;
588 : 16 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
589 : 16 : pp_string (&pp, "Ls");
590 : 16 : pp_unsigned_wide_integer (&pp, arg.linear_step);
591 : 16 : break;
592 : 16 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
593 : 16 : pp_string (&pp, "Us");
594 : 16 : pp_unsigned_wide_integer (&pp, arg.linear_step);
595 : 16 : break;
596 : 8419 : default:
597 : 8419 : pp_character (&pp, 'v');
598 : : }
599 : 14005 : if (arg.alignment)
600 : : {
601 : 656 : pp_character (&pp, 'a');
602 : 656 : pp_decimal_int (&pp, arg.alignment);
603 : : }
604 : : }
605 : :
606 : 8070 : pp_underscore (&pp);
607 : 8070 : const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
608 : 8070 : if (*str == '*')
609 : 16 : ++str;
610 : 8070 : pp_string (&pp, str);
611 : 8070 : str = pp_formatted_text (&pp);
612 : :
613 : : /* If there already is a SIMD clone with the same mangled name, don't
614 : : add another one. This can happen e.g. for
615 : : #pragma omp declare simd
616 : : #pragma omp declare simd simdlen(8)
617 : : int foo (int, int);
618 : : if the simdlen is assumed to be 8 for the first one, etc. */
619 : 33208 : for (struct cgraph_node *clone = node->simd_clones; clone;
620 : 25138 : clone = clone->simdclone->next_clone)
621 : 25636 : if (id_equal (DECL_ASSEMBLER_NAME (clone->decl), str))
622 : : return NULL_TREE;
623 : :
624 : 7572 : return get_identifier (str);
625 : 8070 : }
626 : :
627 : : /* Create a simd clone of OLD_NODE and return it. If FORCE_LOCAL is true,
628 : : create it as a local symbol, otherwise copy the symbol linkage and
629 : : visibility attributes from OLD_NODE. */
630 : :
631 : : static struct cgraph_node *
632 : 7572 : simd_clone_create (struct cgraph_node *old_node, bool force_local)
633 : : {
634 : 7572 : struct cgraph_node *new_node;
635 : 7572 : if (old_node->definition)
636 : : {
637 : 4804 : if (!old_node->has_gimple_body_p ())
638 : : return NULL;
639 : 4804 : old_node->get_body ();
640 : 4804 : new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL,
641 : : NULL, NULL,
642 : : "simdclone");
643 : : }
644 : : else
645 : : {
646 : 2768 : tree old_decl = old_node->decl;
647 : 2768 : tree new_decl = copy_node (old_node->decl);
648 : 2768 : DECL_NAME (new_decl) = clone_function_name_numbered (old_decl,
649 : : "simdclone");
650 : 2768 : SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
651 : 2768 : SET_DECL_RTL (new_decl, NULL);
652 : 2768 : DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
653 : 2768 : DECL_STATIC_DESTRUCTOR (new_decl) = 0;
654 : 2768 : new_node = old_node->create_version_clone (new_decl, vNULL, NULL);
655 : 2768 : if (old_node->in_other_partition)
656 : 16 : new_node->in_other_partition = 1;
657 : : }
658 : 7572 : if (new_node == NULL)
659 : : return new_node;
660 : :
661 : 7572 : set_decl_built_in_function (new_node->decl, NOT_BUILT_IN, 0);
662 : 7572 : if (force_local)
663 : : {
664 : 10 : TREE_PUBLIC (new_node->decl) = 0;
665 : 10 : DECL_COMDAT (new_node->decl) = 0;
666 : 10 : DECL_WEAK (new_node->decl) = 0;
667 : 10 : DECL_EXTERNAL (new_node->decl) = 0;
668 : 10 : DECL_VISIBILITY_SPECIFIED (new_node->decl) = 0;
669 : 10 : DECL_VISIBILITY (new_node->decl) = VISIBILITY_DEFAULT;
670 : 10 : DECL_DLLIMPORT_P (new_node->decl) = 0;
671 : : }
672 : : else
673 : : {
674 : 7562 : TREE_PUBLIC (new_node->decl) = TREE_PUBLIC (old_node->decl);
675 : 7562 : DECL_COMDAT (new_node->decl) = DECL_COMDAT (old_node->decl);
676 : 7562 : DECL_WEAK (new_node->decl) = DECL_WEAK (old_node->decl);
677 : 7562 : DECL_EXTERNAL (new_node->decl) = DECL_EXTERNAL (old_node->decl);
678 : 15124 : DECL_VISIBILITY_SPECIFIED (new_node->decl)
679 : 7562 : = DECL_VISIBILITY_SPECIFIED (old_node->decl);
680 : 7562 : DECL_VISIBILITY (new_node->decl) = DECL_VISIBILITY (old_node->decl);
681 : 7562 : DECL_DLLIMPORT_P (new_node->decl) = DECL_DLLIMPORT_P (old_node->decl);
682 : 7562 : if (DECL_ONE_ONLY (old_node->decl))
683 : 376 : make_decl_one_only (new_node->decl,
684 : : DECL_ASSEMBLER_NAME (new_node->decl));
685 : :
686 : : /* The method cgraph_version_clone_with_body () will force the new
687 : : symbol local. Undo this, and inherit external visibility from
688 : : the old node. */
689 : 7562 : new_node->local = old_node->local;
690 : 7562 : new_node->externally_visible = old_node->externally_visible;
691 : 7562 : new_node->calls_declare_variant_alt
692 : 7562 : = old_node->calls_declare_variant_alt;
693 : : }
694 : :
695 : : /* Mark clones with internal linkage as gc'able, so they will not be
696 : : emitted unless the vectorizer can actually use them. */
697 : 7572 : if (!TREE_PUBLIC (new_node->decl))
698 : 116 : new_node->gc_candidate = true;
699 : :
700 : : return new_node;
701 : : }
702 : :
703 : : /* Adjust the return type of the given function to its appropriate
704 : : vector counterpart. */
705 : :
706 : : static void
707 : 7572 : simd_clone_adjust_return_type (struct cgraph_node *node)
708 : : {
709 : 7572 : tree fndecl = node->decl;
710 : 7572 : tree orig_rettype = TREE_TYPE (TREE_TYPE (fndecl));
711 : 7572 : poly_uint64 veclen;
712 : 7572 : tree t;
713 : :
714 : : /* Adjust the function return type. */
715 : 7572 : if (orig_rettype == void_type_node)
716 : 752 : return;
717 : 6820 : t = TREE_TYPE (TREE_TYPE (fndecl));
718 : 6820 : if (INTEGRAL_TYPE_P (t) || POINTER_TYPE_P (t))
719 : 3427 : veclen = node->simdclone->vecsize_int;
720 : : else
721 : 3393 : veclen = node->simdclone->vecsize_float;
722 : 6820 : if (known_eq (veclen, 0U))
723 : 0 : veclen = node->simdclone->simdlen;
724 : : else
725 : 13640 : veclen = exact_div (veclen, GET_MODE_BITSIZE (SCALAR_TYPE_MODE (t)));
726 : 6820 : if (multiple_p (veclen, node->simdclone->simdlen))
727 : 6578 : veclen = node->simdclone->simdlen;
728 : 6820 : if (POINTER_TYPE_P (t))
729 : 18 : t = pointer_sized_int_node;
730 : 6820 : if (known_eq (veclen, node->simdclone->simdlen))
731 : 6578 : t = build_vector_type (t, node->simdclone->simdlen);
732 : : else
733 : : {
734 : 242 : t = build_vector_type (t, veclen);
735 : 242 : t = build_array_type_nelts (t, exact_div (node->simdclone->simdlen,
736 : : veclen));
737 : : }
738 : 6820 : TREE_TYPE (TREE_TYPE (fndecl)) = t;
739 : : }
740 : :
741 : : /* Each vector argument has a corresponding array to be used locally
742 : : as part of the eventual loop. Create such temporary array and
743 : : return it.
744 : :
745 : : PREFIX is the prefix to be used for the temporary.
746 : :
747 : : TYPE is the inner element type.
748 : :
749 : : SIMDLEN is the number of elements. */
750 : :
751 : : static tree
752 : 6593 : create_tmp_simd_array (const char *prefix, tree type, poly_uint64 simdlen)
753 : : {
754 : 6593 : tree atype = build_array_type_nelts (type, simdlen);
755 : 6593 : tree avar = create_tmp_var_raw (atype, prefix);
756 : 6593 : gimple_add_tmp_var (avar);
757 : 6593 : return avar;
758 : : }
759 : :
760 : : /* Modify the function argument types to their corresponding vector
761 : : counterparts if appropriate. Also, create one array for each simd
762 : : argument to be used locally when using the function arguments as
763 : : part of the loop.
764 : :
765 : : NODE is the function whose arguments are to be adjusted.
766 : :
767 : : If NODE does not represent function definition, returns NULL. Otherwise
768 : : returns an adjustment class that will be filled describing how the argument
769 : : declarations will be remapped. New arguments which are not to be remapped
770 : : are marked with USER_FLAG. */
771 : :
772 : : static void
773 : 7572 : simd_clone_adjust_argument_types (struct cgraph_node *node)
774 : : {
775 : 7572 : auto_vec<tree> args;
776 : :
777 : 7572 : if (node->definition)
778 : 4804 : push_function_arg_decls (&args, node->decl);
779 : : else
780 : 2768 : simd_clone_vector_of_formal_parm_types (&args, node->decl);
781 : 7572 : struct cgraph_simd_clone *sc = node->simdclone;
782 : 7572 : unsigned i, k;
783 : 7572 : poly_uint64 veclen;
784 : 7572 : auto_vec<tree> new_params;
785 : :
786 : 20755 : for (i = 0; i < sc->nargs; ++i)
787 : : {
788 : 13183 : tree parm = NULL_TREE;
789 : 13183 : tree parm_type = NULL_TREE;
790 : 26366 : if (i < args.length())
791 : : {
792 : 13183 : parm = args[i];
793 : 13183 : parm_type = node->definition ? TREE_TYPE (parm) : parm;
794 : : }
795 : :
796 : 13183 : sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
797 : 13183 : sc->args[i].orig_type = parm_type;
798 : :
799 : 13183 : switch (sc->args[i].arg_type)
800 : : {
801 : 4730 : default:
802 : 4730 : new_params.safe_push (parm_type);
803 : 9684 : break;
804 : 224 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
805 : 224 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
806 : 224 : new_params.safe_push (parm_type);
807 : 224 : if (node->definition)
808 : 224 : sc->args[i].simd_array
809 : 224 : = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
810 : 224 : TREE_TYPE (parm_type),
811 : : sc->simdlen);
812 : : break;
813 : 8229 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
814 : 8229 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
815 : 8229 : case SIMD_CLONE_ARG_TYPE_VECTOR:
816 : 8229 : if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type))
817 : 3935 : veclen = sc->vecsize_int;
818 : : else
819 : 4294 : veclen = sc->vecsize_float;
820 : 8229 : if (known_eq (veclen, 0U))
821 : 0 : veclen = sc->simdlen;
822 : : else
823 : 8229 : veclen
824 : 8229 : = exact_div (veclen,
825 : 16458 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type)));
826 : 8229 : if (multiple_p (veclen, sc->simdlen))
827 : 6569 : veclen = sc->simdlen;
828 : 8229 : tree vtype;
829 : 8229 : if (POINTER_TYPE_P (parm_type))
830 : 942 : vtype = build_vector_type (pointer_sized_int_node, veclen);
831 : : else
832 : 7287 : vtype = build_vector_type (parm_type, veclen);
833 : 8229 : sc->args[i].vector_type = vtype;
834 : 8229 : k = vector_unroll_factor (sc->simdlen, veclen);
835 : 18620 : for (unsigned j = 0; j < k; j++)
836 : 10391 : new_params.safe_push (vtype);
837 : :
838 : 8229 : if (node->definition)
839 : 4809 : sc->args[i].simd_array
840 : 9602 : = create_tmp_simd_array (DECL_NAME (parm)
841 : 4793 : ? IDENTIFIER_POINTER (DECL_NAME (parm))
842 : : : NULL, parm_type, sc->simdlen);
843 : : }
844 : : }
845 : :
846 : 7572 : if (sc->inbranch)
847 : : {
848 : 2313 : tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
849 : 2313 : tree mask_type;
850 : 2313 : if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
851 : 1703 : veclen = sc->vecsize_int;
852 : : else
853 : 610 : veclen = sc->vecsize_float;
854 : 2313 : if (known_eq (veclen, 0U))
855 : 0 : veclen = sc->simdlen;
856 : : else
857 : 4626 : veclen = exact_div (veclen,
858 : 4626 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type)));
859 : 2313 : if (multiple_p (veclen, sc->simdlen))
860 : 2209 : veclen = sc->simdlen;
861 : 2313 : if (sc->mask_mode != VOIDmode)
862 : 567 : mask_type
863 : 567 : = lang_hooks.types.type_for_mode (sc->mask_mode, 1);
864 : 1746 : else if (POINTER_TYPE_P (base_type))
865 : 7 : mask_type = build_vector_type (pointer_sized_int_node, veclen);
866 : : else
867 : 1739 : mask_type = build_vector_type (base_type, veclen);
868 : :
869 : 2313 : k = vector_unroll_factor (sc->simdlen, veclen);
870 : :
871 : : /* We have previously allocated one extra entry for the mask. Use
872 : : it and fill it. */
873 : 2313 : sc->nargs++;
874 : 2313 : if (sc->mask_mode != VOIDmode)
875 : 567 : base_type = boolean_type_node;
876 : 2313 : if (node->definition)
877 : : {
878 : 2065 : sc->args[i].orig_arg
879 : 2065 : = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type);
880 : 2065 : if (sc->mask_mode == VOIDmode)
881 : 1560 : sc->args[i].simd_array
882 : 1560 : = create_tmp_simd_array ("mask", base_type, sc->simdlen);
883 : 505 : else if (k > 1)
884 : 0 : sc->args[i].simd_array
885 : 0 : = create_tmp_simd_array ("mask", mask_type, k);
886 : : else
887 : 505 : sc->args[i].simd_array = NULL_TREE;
888 : : }
889 : 2313 : sc->args[i].orig_type = base_type;
890 : 2313 : sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK;
891 : 2313 : sc->args[i].vector_type = mask_type;
892 : : }
893 : :
894 : 7572 : if (!node->definition)
895 : : {
896 : 2768 : tree new_arg_types = NULL_TREE, new_reversed;
897 : 2768 : bool last_parm_void = false;
898 : 5536 : if (args.length () > 0 && args.last () == void_type_node)
899 : : last_parm_void = true;
900 : :
901 : 2768 : gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
902 : 13946 : for (i = 0; i < new_params.length (); i++)
903 : 4205 : new_arg_types = tree_cons (NULL_TREE, new_params[i], new_arg_types);
904 : 2768 : new_reversed = nreverse (new_arg_types);
905 : 2768 : if (last_parm_void)
906 : : {
907 : 2768 : if (new_reversed)
908 : 2768 : TREE_CHAIN (new_arg_types) = void_list_node;
909 : : else
910 : 0 : new_reversed = void_list_node;
911 : : }
912 : 2768 : TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed;
913 : : }
914 : 7572 : }
915 : :
916 : : /* Initialize and copy the function arguments in NODE to their
917 : : corresponding local simd arrays. Returns a fresh gimple_seq with
918 : : the instruction sequence generated. */
919 : :
920 : : static gimple_seq
921 : 4804 : simd_clone_init_simd_arrays (struct cgraph_node *node,
922 : : ipa_param_body_adjustments *adjustments)
923 : : {
924 : 4804 : gimple_seq seq = NULL;
925 : 4804 : unsigned i = 0, j = 0, k;
926 : :
927 : 4804 : for (tree arg = DECL_ARGUMENTS (node->decl);
928 : 16164 : arg;
929 : 11360 : arg = DECL_CHAIN (arg), i++, j++)
930 : : {
931 : 11360 : ipa_adjusted_param adj = (*adjustments->m_adj_params)[j];
932 : 15846 : if (adj.op == IPA_PARAM_OP_COPY
933 : 11360 : || POINTER_TYPE_P (TREE_TYPE (arg)))
934 : 9477 : continue;
935 : :
936 : 6874 : node->simdclone->args[i].vector_arg = arg;
937 : :
938 : 6874 : tree array = node->simdclone->args[i].simd_array;
939 : 6874 : if (node->simdclone->mask_mode != VOIDmode
940 : 1659 : && adj.param_prefix_index == IPA_PARAM_PREFIX_MASK)
941 : : {
942 : 505 : if (array == NULL_TREE)
943 : 505 : continue;
944 : 0 : unsigned int l
945 : 0 : = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array))));
946 : 0 : for (k = 0; k <= l; k++)
947 : : {
948 : 0 : if (k)
949 : : {
950 : 0 : arg = DECL_CHAIN (arg);
951 : 0 : j++;
952 : : }
953 : 0 : tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
954 : : array, size_int (k), NULL, NULL);
955 : 0 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
956 : 0 : gimplify_and_add (t, &seq);
957 : : }
958 : 0 : continue;
959 : 0 : }
960 : 6369 : if (!VECTOR_TYPE_P (TREE_TYPE (arg))
961 : 6369 : || known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)),
962 : : node->simdclone->simdlen))
963 : : {
964 : 4820 : tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
965 : 4820 : tree ptr = build_fold_addr_expr (array);
966 : 4820 : tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
967 : 4820 : build_int_cst (ptype, 0));
968 : 4820 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
969 : 4820 : gimplify_and_add (t, &seq);
970 : : }
971 : : else
972 : : {
973 : 1549 : poly_uint64 simdlen = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg));
974 : 1549 : unsigned int times = vector_unroll_factor (node->simdclone->simdlen,
975 : : simdlen);
976 : 1549 : tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
977 : 5059 : for (k = 0; k < times; k++)
978 : : {
979 : 3510 : tree ptr = build_fold_addr_expr (array);
980 : 3510 : int elemsize;
981 : 3510 : if (k)
982 : : {
983 : 1961 : arg = DECL_CHAIN (arg);
984 : 1961 : j++;
985 : : }
986 : 3510 : tree elemtype = TREE_TYPE (TREE_TYPE (arg));
987 : 3510 : elemsize = GET_MODE_SIZE (SCALAR_TYPE_MODE (elemtype));
988 : 3510 : tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
989 : 3510 : build_int_cst (ptype, k * elemsize * simdlen));
990 : 3510 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
991 : 3510 : gimplify_and_add (t, &seq);
992 : : }
993 : : }
994 : : }
995 : 4804 : return seq;
996 : : }
997 : :
998 : : /* Callback info for ipa_simd_modify_stmt_ops below. */
999 : :
1000 : : struct modify_stmt_info {
1001 : : ipa_param_body_adjustments *adjustments;
1002 : : gimple *stmt;
1003 : : gimple *after_stmt;
1004 : : /* True if the parent statement was modified by
1005 : : ipa_simd_modify_stmt_ops. */
1006 : : bool modified;
1007 : : };
1008 : :
1009 : : /* Callback for walk_gimple_op.
1010 : :
1011 : : Adjust operands from a given statement as specified in the
1012 : : adjustments vector in the callback data. */
1013 : :
1014 : : static tree
1015 : 108627 : ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
1016 : : {
1017 : 108627 : struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1018 : 108627 : struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
1019 : 108627 : tree *orig_tp = tp;
1020 : 108627 : if (TREE_CODE (*tp) == ADDR_EXPR)
1021 : 7240 : tp = &TREE_OPERAND (*tp, 0);
1022 : :
1023 : 108627 : if (TREE_CODE (*tp) == BIT_FIELD_REF
1024 : 108627 : || TREE_CODE (*tp) == IMAGPART_EXPR
1025 : 108627 : || TREE_CODE (*tp) == REALPART_EXPR)
1026 : 0 : tp = &TREE_OPERAND (*tp, 0);
1027 : :
1028 : 108627 : tree repl = NULL_TREE;
1029 : 108627 : ipa_param_body_replacement *pbr = NULL;
1030 : :
1031 : 108627 : if (TREE_CODE (*tp) == PARM_DECL)
1032 : : {
1033 : 2494 : pbr = info->adjustments->get_expr_replacement (*tp, true);
1034 : 2494 : if (pbr)
1035 : 1616 : repl = pbr->repl;
1036 : : }
1037 : 106133 : else if (TYPE_P (*tp))
1038 : 0 : *walk_subtrees = 0;
1039 : :
1040 : 1616 : if (repl)
1041 : 1616 : repl = unshare_expr (repl);
1042 : : else
1043 : : {
1044 : 107011 : if (tp != orig_tp)
1045 : : {
1046 : 6324 : *walk_subtrees = 0;
1047 : 6324 : bool modified = info->modified;
1048 : 6324 : info->modified = false;
1049 : 6324 : walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset);
1050 : 6324 : if (!info->modified)
1051 : : {
1052 : 6096 : info->modified = modified;
1053 : 6096 : return NULL_TREE;
1054 : : }
1055 : 228 : info->modified = modified;
1056 : 228 : repl = *tp;
1057 : : }
1058 : : else
1059 : : return NULL_TREE;
1060 : : }
1061 : :
1062 : 1844 : if (tp != orig_tp)
1063 : : {
1064 : 1144 : if (gimple_code (info->stmt) == GIMPLE_PHI
1065 : 56 : && pbr
1066 : 48 : && TREE_CODE (*orig_tp) == ADDR_EXPR
1067 : 48 : && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL
1068 : 1192 : && pbr->dummy)
1069 : : {
1070 : 0 : gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME);
1071 : 0 : *orig_tp = pbr->dummy;
1072 : 0 : info->modified = true;
1073 : 0 : return NULL_TREE;
1074 : : }
1075 : :
1076 : 1144 : repl = build_fold_addr_expr (repl);
1077 : 1144 : gimple *stmt;
1078 : 1144 : if (is_gimple_debug (info->stmt))
1079 : : {
1080 : 108 : tree vexpr = build_debug_expr_decl (TREE_TYPE (repl));
1081 : 108 : stmt = gimple_build_debug_source_bind (vexpr, repl, NULL);
1082 : 108 : repl = vexpr;
1083 : : }
1084 : : else
1085 : : {
1086 : 1036 : stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
1087 : 1036 : repl = gimple_assign_lhs (stmt);
1088 : : }
1089 : 1144 : gimple_stmt_iterator gsi;
1090 : 1144 : if (gimple_code (info->stmt) == GIMPLE_PHI)
1091 : : {
1092 : 56 : if (info->after_stmt)
1093 : 8 : gsi = gsi_for_stmt (info->after_stmt);
1094 : : else
1095 : 48 : gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
1096 : : /* Cache SSA_NAME for next time. */
1097 : 56 : if (pbr
1098 : 48 : && TREE_CODE (*orig_tp) == ADDR_EXPR
1099 : 104 : && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL)
1100 : : {
1101 : 48 : gcc_assert (!pbr->dummy);
1102 : 48 : pbr->dummy = repl;
1103 : : }
1104 : : }
1105 : : else
1106 : 1088 : gsi = gsi_for_stmt (info->stmt);
1107 : 1144 : if (info->after_stmt)
1108 : 8 : gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
1109 : : else
1110 : 1136 : gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1111 : 1144 : if (gimple_code (info->stmt) == GIMPLE_PHI)
1112 : 56 : info->after_stmt = stmt;
1113 : 1144 : *orig_tp = repl;
1114 : : }
1115 : 700 : else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
1116 : : {
1117 : 0 : tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
1118 : 0 : *tp = vce;
1119 : : }
1120 : : else
1121 : 700 : *tp = repl;
1122 : :
1123 : 1844 : info->modified = true;
1124 : 1844 : return NULL_TREE;
1125 : : }
1126 : :
1127 : : /* Traverse the function body and perform all modifications as
1128 : : described in ADJUSTMENTS. At function return, ADJUSTMENTS will be
1129 : : modified such that the replacement/reduction value will now be an
1130 : : offset into the corresponding simd_array.
1131 : :
1132 : : This function will replace all function argument uses with their
1133 : : corresponding simd array elements, and ajust the return values
1134 : : accordingly. */
1135 : :
1136 : : static void
1137 : 4804 : ipa_simd_modify_function_body (struct cgraph_node *node,
1138 : : ipa_param_body_adjustments *adjustments,
1139 : : tree retval_array, tree iter)
1140 : : {
1141 : 4804 : basic_block bb;
1142 : 4804 : unsigned int i, j;
1143 : :
1144 : :
1145 : : /* Register replacements for every function argument use to an offset into
1146 : : the corresponding simd_array. */
1147 : 16164 : for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
1148 : : {
1149 : 17911 : if (!node->simdclone->args[i].vector_arg
1150 : 11360 : || (*adjustments->m_adj_params)[j].user_flag)
1151 : 6551 : continue;
1152 : :
1153 : 4809 : tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1154 : 4809 : tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
1155 : 4809 : tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
1156 : : iter, NULL_TREE, NULL_TREE);
1157 : 4809 : adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
1158 : :
1159 : 4809 : if (multiple_p (node->simdclone->simdlen, TYPE_VECTOR_SUBPARTS (vectype)))
1160 : 4809 : j += vector_unroll_factor (node->simdclone->simdlen,
1161 : 4809 : TYPE_VECTOR_SUBPARTS (vectype)) - 1;
1162 : : }
1163 : 4804 : adjustments->sort_replacements ();
1164 : :
1165 : 4804 : tree name;
1166 : 47151 : FOR_EACH_SSA_NAME (i, name, cfun)
1167 : : {
1168 : 42347 : tree base_var;
1169 : 42347 : if (SSA_NAME_VAR (name)
1170 : 24981 : && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
1171 : 8845 : && (base_var
1172 : 8845 : = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
1173 : : {
1174 : 4783 : if (SSA_NAME_IS_DEFAULT_DEF (name))
1175 : : {
1176 : 4311 : tree old_decl = SSA_NAME_VAR (name);
1177 : 4311 : bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1178 : 4311 : gimple_stmt_iterator gsi = gsi_after_labels (bb);
1179 : 4311 : tree repl = adjustments->lookup_replacement (old_decl, 0);
1180 : 4311 : gcc_checking_assert (repl);
1181 : 4311 : repl = unshare_expr (repl);
1182 : 4311 : set_ssa_default_def (cfun, old_decl, NULL_TREE);
1183 : 4311 : SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1184 : 4311 : SSA_NAME_IS_DEFAULT_DEF (name) = 0;
1185 : 4311 : gimple *stmt = gimple_build_assign (name, repl);
1186 : 4311 : gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1187 : : }
1188 : : else
1189 : 944 : SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1190 : : }
1191 : : }
1192 : :
1193 : 4804 : struct modify_stmt_info info;
1194 : 4804 : info.adjustments = adjustments;
1195 : :
1196 : 19874 : FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
1197 : : {
1198 : 15070 : gimple_stmt_iterator gsi;
1199 : :
1200 : 17374 : for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1201 : : {
1202 : 2304 : gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
1203 : 2304 : int i, n = gimple_phi_num_args (phi);
1204 : 2304 : info.stmt = phi;
1205 : 2304 : info.after_stmt = NULL;
1206 : 2304 : struct walk_stmt_info wi;
1207 : 2304 : memset (&wi, 0, sizeof (wi));
1208 : 2304 : info.modified = false;
1209 : 2304 : wi.info = &info;
1210 : 6928 : for (i = 0; i < n; ++i)
1211 : : {
1212 : 4624 : int walk_subtrees = 1;
1213 : 4624 : tree arg = gimple_phi_arg_def (phi, i);
1214 : 4624 : tree op = arg;
1215 : 4624 : ipa_simd_modify_stmt_ops (&op, &walk_subtrees, &wi);
1216 : 4624 : if (op != arg)
1217 : : {
1218 : 48 : SET_PHI_ARG_DEF (phi, i, op);
1219 : 48 : gcc_assert (TREE_CODE (op) == SSA_NAME);
1220 : 48 : if (gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL)
1221 : 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
1222 : : }
1223 : : }
1224 : : }
1225 : :
1226 : 15070 : gsi = gsi_start_bb (bb);
1227 : 62571 : while (!gsi_end_p (gsi))
1228 : : {
1229 : 47501 : gimple *stmt = gsi_stmt (gsi);
1230 : 47501 : info.stmt = stmt;
1231 : 47501 : info.after_stmt = NULL;
1232 : 47501 : struct walk_stmt_info wi;
1233 : :
1234 : 47501 : memset (&wi, 0, sizeof (wi));
1235 : 47501 : info.modified = false;
1236 : 47501 : wi.info = &info;
1237 : 47501 : walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
1238 : :
1239 : 47501 : if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
1240 : : {
1241 : 4708 : tree retval = gimple_return_retval (return_stmt);
1242 : 4708 : edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
1243 : 4708 : e->flags |= EDGE_FALLTHRU;
1244 : 4708 : if (!retval)
1245 : : {
1246 : 712 : gsi_remove (&gsi, true);
1247 : 736 : continue;
1248 : : }
1249 : :
1250 : : /* Replace `return foo' with `retval_array[iter] = foo'. */
1251 : 3996 : tree ref = build4 (ARRAY_REF, TREE_TYPE (retval),
1252 : : retval_array, iter, NULL, NULL);
1253 : 3996 : stmt = gimple_build_assign (ref, retval);
1254 : 3996 : gsi_replace (&gsi, stmt, true);
1255 : 3996 : info.modified = true;
1256 : : }
1257 : :
1258 : 46789 : if (info.modified)
1259 : : {
1260 : 5384 : update_stmt (stmt);
1261 : : /* If the above changed the var of a debug bind into something
1262 : : different, remove the debug stmt. We could also for all the
1263 : : replaced parameters add VAR_DECLs for debug info purposes,
1264 : : add debug stmts for those to be the simd array accesses and
1265 : : replace debug stmt var operand with that var. Debugging of
1266 : : vectorized loops doesn't work too well, so don't bother for
1267 : : now. */
1268 : 5452 : if ((gimple_debug_bind_p (stmt)
1269 : 92 : && !DECL_P (gimple_debug_bind_get_var (stmt)))
1270 : 160 : || (gimple_debug_source_bind_p (stmt)
1271 : 0 : && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
1272 : : {
1273 : 24 : gsi_remove (&gsi, true);
1274 : 24 : continue;
1275 : : }
1276 : 5360 : if (maybe_clean_eh_stmt (stmt))
1277 : 0 : gimple_purge_dead_eh_edges (gimple_bb (stmt));
1278 : : }
1279 : 46765 : gsi_next (&gsi);
1280 : : }
1281 : : }
1282 : 4804 : }
1283 : :
1284 : : /* Helper function of simd_clone_adjust, return linear step addend
1285 : : of Ith argument. */
1286 : :
1287 : : static tree
1288 : 2407 : simd_clone_linear_addend (struct cgraph_node *node, unsigned int i,
1289 : : tree addtype, basic_block entry_bb)
1290 : : {
1291 : 2407 : tree ptype = NULL_TREE;
1292 : 2407 : switch (node->simdclone->args[i].arg_type)
1293 : : {
1294 : 2219 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
1295 : 2219 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
1296 : 2219 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1297 : 2219 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
1298 : 2219 : return build_int_cst (addtype, node->simdclone->args[i].linear_step);
1299 : 172 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
1300 : 172 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
1301 : 172 : ptype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1302 : 172 : break;
1303 : 16 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1304 : 16 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1305 : 16 : ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg));
1306 : 16 : break;
1307 : 0 : default:
1308 : 0 : gcc_unreachable ();
1309 : : }
1310 : :
1311 : 188 : unsigned int idx = node->simdclone->args[i].linear_step;
1312 : 188 : tree arg = node->simdclone->args[idx].orig_arg;
1313 : 188 : gcc_assert (is_gimple_reg_type (TREE_TYPE (arg)));
1314 : 188 : gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1315 : 188 : gimple *g;
1316 : 188 : tree ret;
1317 : 188 : if (is_gimple_reg (arg))
1318 : 188 : ret = get_or_create_ssa_default_def (cfun, arg);
1319 : : else
1320 : : {
1321 : 0 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
1322 : 0 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1323 : 0 : ret = gimple_assign_lhs (g);
1324 : : }
1325 : 188 : if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
1326 : : {
1327 : 32 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))),
1328 : : build_simple_mem_ref (ret));
1329 : 32 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1330 : 32 : ret = gimple_assign_lhs (g);
1331 : : }
1332 : 188 : if (!useless_type_conversion_p (addtype, TREE_TYPE (ret)))
1333 : : {
1334 : 72 : g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret);
1335 : 72 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1336 : 72 : ret = gimple_assign_lhs (g);
1337 : : }
1338 : 188 : if (POINTER_TYPE_P (ptype))
1339 : : {
1340 : 72 : tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype));
1341 : 72 : if (size && TREE_CODE (size) == INTEGER_CST)
1342 : : {
1343 : 72 : g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR,
1344 : : ret, fold_convert (addtype, size));
1345 : 72 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1346 : 72 : ret = gimple_assign_lhs (g);
1347 : : }
1348 : : }
1349 : : return ret;
1350 : : }
1351 : :
1352 : : /* Adjust the argument types in NODE to their appropriate vector
1353 : : counterparts. */
1354 : :
1355 : : static void
1356 : 4804 : simd_clone_adjust (struct cgraph_node *node)
1357 : : {
1358 : 4804 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
1359 : :
1360 : 4804 : tree orig_rettype = TREE_TYPE (TREE_TYPE (node->decl));
1361 : 4804 : TREE_TYPE (node->decl) = build_distinct_type_copy (TREE_TYPE (node->decl));
1362 : 4804 : simd_clone_adjust_return_type (node);
1363 : 4804 : simd_clone_adjust_argument_types (node);
1364 : 4804 : targetm.simd_clone.adjust (node);
1365 : 4804 : tree retval = NULL_TREE;
1366 : 4804 : if (orig_rettype != void_type_node)
1367 : : {
1368 : 4060 : poly_uint64 veclen;
1369 : 4060 : if (INTEGRAL_TYPE_P (orig_rettype) || POINTER_TYPE_P (orig_rettype))
1370 : 3115 : veclen = node->simdclone->vecsize_int;
1371 : : else
1372 : 945 : veclen = node->simdclone->vecsize_float;
1373 : 4060 : if (known_eq (veclen, 0U))
1374 : 0 : veclen = node->simdclone->simdlen;
1375 : : else
1376 : 8120 : veclen = exact_div (veclen,
1377 : 8120 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (orig_rettype)));
1378 : 4060 : if (multiple_p (veclen, node->simdclone->simdlen))
1379 : 3845 : veclen = node->simdclone->simdlen;
1380 : :
1381 : 4060 : retval = DECL_RESULT (node->decl);
1382 : : /* Adjust the DECL_RESULT. */
1383 : 4060 : TREE_TYPE (retval) = TREE_TYPE (TREE_TYPE (node->decl));
1384 : 4060 : relayout_decl (retval);
1385 : :
1386 : 8120 : tree atype = build_array_type_nelts (orig_rettype,
1387 : 4060 : node->simdclone->simdlen);
1388 : 4060 : if (maybe_ne (veclen, node->simdclone->simdlen))
1389 : 215 : retval = build1 (VIEW_CONVERT_EXPR, atype, retval);
1390 : : else
1391 : : {
1392 : : /* Set up a SIMD array to use as the return value. */
1393 : 3845 : retval = create_tmp_var_raw (atype, "retval");
1394 : 3845 : gimple_add_tmp_var (retval);
1395 : : }
1396 : : }
1397 : :
1398 : 4804 : struct cgraph_simd_clone *sc = node->simdclone;
1399 : 4804 : vec<ipa_adjusted_param, va_gc> *new_params = NULL;
1400 : 4804 : vec_safe_reserve (new_params, sc->nargs);
1401 : 4804 : unsigned i, j, k;
1402 : 16164 : for (i = 0; i < sc->nargs; ++i)
1403 : : {
1404 : 11360 : ipa_adjusted_param adj;
1405 : 11360 : memset (&adj, 0, sizeof (adj));
1406 : 11360 : poly_uint64 veclen;
1407 : 11360 : tree elem_type;
1408 : :
1409 : 11360 : adj.base_index = i;
1410 : 11360 : adj.prev_clone_index = i;
1411 : 11360 : switch (sc->args[i].arg_type)
1412 : : {
1413 : 4470 : default:
1414 : : /* No adjustment necessary for scalar arguments. */
1415 : 4470 : adj.op = IPA_PARAM_OP_COPY;
1416 : 4470 : break;
1417 : 16 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1418 : 16 : adj.op = IPA_PARAM_OP_COPY;
1419 : 16 : break;
1420 : 6874 : case SIMD_CLONE_ARG_TYPE_MASK:
1421 : 6874 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1422 : 6874 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1423 : 6874 : case SIMD_CLONE_ARG_TYPE_VECTOR:
1424 : 6874 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK
1425 : 2065 : && sc->mask_mode != VOIDmode)
1426 : 505 : elem_type = boolean_type_node;
1427 : : else
1428 : 6369 : elem_type = TREE_TYPE (sc->args[i].vector_type);
1429 : 6874 : if (INTEGRAL_TYPE_P (elem_type) || POINTER_TYPE_P (elem_type))
1430 : 5223 : veclen = sc->vecsize_int;
1431 : : else
1432 : 1651 : veclen = sc->vecsize_float;
1433 : 6874 : if (known_eq (veclen, 0U))
1434 : 0 : veclen = sc->simdlen;
1435 : : else
1436 : 6874 : veclen
1437 : 6874 : = exact_div (veclen,
1438 : 13748 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (elem_type)));
1439 : 6874 : if (multiple_p (veclen, sc->simdlen))
1440 : 5325 : veclen = sc->simdlen;
1441 : 6874 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
1442 : : {
1443 : 2065 : adj.user_flag = 1;
1444 : 2065 : adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
1445 : : }
1446 : : else
1447 : 4809 : adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
1448 : 6874 : adj.op = IPA_PARAM_OP_NEW;
1449 : 6874 : adj.type = sc->args[i].vector_type;
1450 : 6874 : k = vector_unroll_factor (sc->simdlen, veclen);
1451 : 8835 : for (j = 1; j < k; j++)
1452 : : {
1453 : 1961 : vec_safe_push (new_params, adj);
1454 : 1961 : if (j == 1)
1455 : : {
1456 : 1549 : memset (&adj, 0, sizeof (adj));
1457 : 1549 : adj.op = IPA_PARAM_OP_NEW;
1458 : 1549 : adj.user_flag = 1;
1459 : 1549 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
1460 : 92 : adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
1461 : : else
1462 : 1457 : adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
1463 : 1549 : adj.base_index = i;
1464 : 1549 : adj.prev_clone_index = i;
1465 : 1549 : adj.type = sc->args[i].vector_type;
1466 : : }
1467 : : }
1468 : : }
1469 : 11360 : vec_safe_push (new_params, adj);
1470 : : }
1471 : 4804 : ipa_param_body_adjustments *adjustments
1472 : 4804 : = new ipa_param_body_adjustments (new_params, node->decl);
1473 : 4804 : adjustments->modify_formal_parameters ();
1474 : :
1475 : 4804 : push_gimplify_context ();
1476 : :
1477 : 4804 : gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments);
1478 : :
1479 : : /* Adjust all uses of vector arguments accordingly. Adjust all
1480 : : return values accordingly. */
1481 : 4804 : tree iter = create_tmp_var (unsigned_type_node, "iter");
1482 : 4804 : tree iter1 = make_ssa_name (iter);
1483 : 4804 : tree iter2 = NULL_TREE;
1484 : 4804 : ipa_simd_modify_function_body (node, adjustments, retval, iter1);
1485 : 4804 : delete adjustments;
1486 : :
1487 : : /* Initialize the iteration variable. */
1488 : 4804 : basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1489 : 4804 : basic_block body_bb = split_block_after_labels (entry_bb)->dest;
1490 : 4804 : gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1491 : : /* Insert the SIMD array and iv initialization at function
1492 : : entry. */
1493 : 4804 : gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
1494 : :
1495 : 4804 : pop_gimplify_context (NULL);
1496 : :
1497 : 4804 : gimple *g;
1498 : 4804 : basic_block incr_bb = NULL;
1499 : 4804 : class loop *loop = NULL;
1500 : :
1501 : : /* Create a new BB right before the original exit BB, to hold the
1502 : : iteration increment and the condition/branch. */
1503 : 4804 : if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1504 : : {
1505 : 4668 : basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
1506 : 4668 : incr_bb = create_empty_bb (orig_exit);
1507 : 4668 : incr_bb->count = profile_count::zero ();
1508 : 4668 : add_bb_to_loop (incr_bb, body_bb->loop_father);
1509 : 14044 : while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1510 : : {
1511 : 4708 : edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1512 : 4708 : redirect_edge_succ (e, incr_bb);
1513 : 4708 : incr_bb->count += e->count ();
1514 : : }
1515 : : }
1516 : 136 : else if (node->simdclone->inbranch)
1517 : : {
1518 : 68 : incr_bb = create_empty_bb (entry_bb);
1519 : 68 : incr_bb->count = profile_count::zero ();
1520 : 68 : add_bb_to_loop (incr_bb, body_bb->loop_father);
1521 : : }
1522 : :
1523 : 68 : if (incr_bb)
1524 : : {
1525 : 4736 : make_single_succ_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1526 : 4736 : gsi = gsi_last_bb (incr_bb);
1527 : 4736 : iter2 = make_ssa_name (iter);
1528 : 4736 : g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
1529 : 4736 : build_int_cst (unsigned_type_node, 1));
1530 : 4736 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1531 : :
1532 : : /* Mostly annotate the loop for the vectorizer (the rest is done
1533 : : below). */
1534 : 4736 : loop = alloc_loop ();
1535 : 4736 : cfun->has_force_vectorize_loops = true;
1536 : : /* For now, simlen is always constant. */
1537 : 4736 : loop->safelen = node->simdclone->simdlen.to_constant ();
1538 : 4736 : loop->force_vectorize = true;
1539 : 4736 : loop->header = body_bb;
1540 : : }
1541 : :
1542 : : /* Branch around the body if the mask applies. */
1543 : 4804 : if (node->simdclone->inbranch)
1544 : : {
1545 : 2065 : gsi = gsi_last_bb (loop->header);
1546 : 2065 : tree mask_array
1547 : 2065 : = node->simdclone->args[node->simdclone->nargs - 1].simd_array;
1548 : 2065 : tree mask;
1549 : 2065 : if (node->simdclone->mask_mode != VOIDmode)
1550 : : {
1551 : 505 : tree shift_cnt;
1552 : 505 : if (mask_array == NULL_TREE)
1553 : : {
1554 : 505 : tree arg = node->simdclone->args[node->simdclone->nargs
1555 : : - 1].vector_arg;
1556 : 505 : mask = get_or_create_ssa_default_def (cfun, arg);
1557 : 505 : shift_cnt = iter1;
1558 : : }
1559 : : else
1560 : : {
1561 : 0 : tree maskt = TREE_TYPE (mask_array);
1562 : 0 : int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt)));
1563 : : /* For now, c must be constant here. */
1564 : 0 : c = exact_div (node->simdclone->simdlen, c + 1).to_constant ();
1565 : 0 : int s = exact_log2 (c);
1566 : 0 : gcc_assert (s > 0);
1567 : 0 : c--;
1568 : 0 : tree idx = make_ssa_name (TREE_TYPE (iter1));
1569 : 0 : g = gimple_build_assign (idx, RSHIFT_EXPR, iter1,
1570 : : build_int_cst (NULL_TREE, s));
1571 : 0 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1572 : 0 : mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1573 : 0 : tree aref = build4 (ARRAY_REF,
1574 : 0 : TREE_TYPE (TREE_TYPE (mask_array)),
1575 : : mask_array, idx, NULL, NULL);
1576 : 0 : g = gimple_build_assign (mask, aref);
1577 : 0 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1578 : 0 : shift_cnt = make_ssa_name (TREE_TYPE (iter1));
1579 : 0 : g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1,
1580 : 0 : build_int_cst (TREE_TYPE (iter1), c));
1581 : 0 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1582 : : }
1583 : 505 : tree shift_cnt_conv = shift_cnt;
1584 : 505 : if (!useless_type_conversion_p (TREE_TYPE (mask),
1585 : 505 : TREE_TYPE (shift_cnt)))
1586 : : {
1587 : 7 : shift_cnt_conv = make_ssa_name (TREE_TYPE (mask));
1588 : 7 : g = gimple_build_assign (shift_cnt_conv, NOP_EXPR, shift_cnt);
1589 : 7 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1590 : : }
1591 : 505 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1592 : : RSHIFT_EXPR, mask, shift_cnt_conv);
1593 : 505 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1594 : 505 : mask = gimple_assign_lhs (g);
1595 : 505 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1596 : : BIT_AND_EXPR, mask,
1597 : 505 : build_one_cst (TREE_TYPE (mask)));
1598 : 505 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1599 : 505 : mask = gimple_assign_lhs (g);
1600 : : }
1601 : : else
1602 : : {
1603 : 1560 : mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1604 : 1560 : tree aref = build4 (ARRAY_REF,
1605 : 1560 : TREE_TYPE (TREE_TYPE (mask_array)),
1606 : : mask_array, iter1, NULL, NULL);
1607 : 1560 : g = gimple_build_assign (mask, aref);
1608 : 1560 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1609 : 1560 : int bitsize = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (aref)));
1610 : 1560 : if (!INTEGRAL_TYPE_P (TREE_TYPE (aref)))
1611 : : {
1612 : 352 : aref = build1 (VIEW_CONVERT_EXPR,
1613 : : build_nonstandard_integer_type (bitsize, 0),
1614 : : mask);
1615 : 352 : mask = make_ssa_name (TREE_TYPE (aref));
1616 : 352 : g = gimple_build_assign (mask, aref);
1617 : 352 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1618 : : }
1619 : : }
1620 : :
1621 : 2065 : g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)),
1622 : : NULL, NULL);
1623 : 2065 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1624 : 2065 : edge e = make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE);
1625 : 2065 : e->probability = profile_probability::unlikely ().guessed ();
1626 : 2065 : incr_bb->count += e->count ();
1627 : 2065 : edge fallthru = FALLTHRU_EDGE (loop->header);
1628 : 2065 : fallthru->flags = EDGE_FALSE_VALUE;
1629 : 2065 : fallthru->probability = profile_probability::likely ().guessed ();
1630 : : }
1631 : :
1632 : 4804 : basic_block latch_bb = NULL;
1633 : 4804 : basic_block new_exit_bb = NULL;
1634 : :
1635 : : /* Generate the condition. */
1636 : 4804 : if (incr_bb)
1637 : : {
1638 : 4736 : gsi = gsi_last_bb (incr_bb);
1639 : 4736 : g = gimple_build_cond (LT_EXPR, iter2,
1640 : : build_int_cst (unsigned_type_node,
1641 : 4736 : node->simdclone->simdlen),
1642 : : NULL, NULL);
1643 : 4736 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1644 : 4736 : edge e = split_block (incr_bb, gsi_stmt (gsi));
1645 : 4736 : latch_bb = e->dest;
1646 : 4736 : new_exit_bb = split_block_after_labels (latch_bb)->dest;
1647 : 4736 : loop->latch = latch_bb;
1648 : :
1649 : 4736 : redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
1650 : :
1651 : 4736 : edge new_e = make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
1652 : :
1653 : : /* FIXME: Do we need to distribute probabilities for the conditional? */
1654 : 4736 : new_e->probability = profile_probability::guessed_never ();
1655 : : /* The successor of incr_bb is already pointing to latch_bb; just
1656 : : change the flags.
1657 : : make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE); */
1658 : 4736 : FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
1659 : : }
1660 : :
1661 : 4804 : gphi *phi = create_phi_node (iter1, body_bb);
1662 : 4804 : edge preheader_edge = find_edge (entry_bb, body_bb);
1663 : 4804 : edge latch_edge = NULL;
1664 : 4804 : add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
1665 : : UNKNOWN_LOCATION);
1666 : 4804 : if (incr_bb)
1667 : : {
1668 : 4736 : latch_edge = single_succ_edge (latch_bb);
1669 : 4736 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1670 : :
1671 : : /* Generate the new return. */
1672 : 4736 : gsi = gsi_last_bb (new_exit_bb);
1673 : 4736 : if (retval
1674 : 4044 : && TREE_CODE (retval) == VIEW_CONVERT_EXPR
1675 : 4951 : && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
1676 : 215 : retval = TREE_OPERAND (retval, 0);
1677 : 4521 : else if (retval)
1678 : : {
1679 : 3829 : retval = build1 (VIEW_CONVERT_EXPR,
1680 : 3829 : TREE_TYPE (TREE_TYPE (node->decl)),
1681 : : retval);
1682 : 3829 : retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
1683 : : false, GSI_CONTINUE_LINKING);
1684 : : }
1685 : 4736 : g = gimple_build_return (retval);
1686 : 4736 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1687 : : }
1688 : :
1689 : : /* Handle aligned clauses by replacing default defs of the aligned
1690 : : uniform args with __builtin_assume_aligned (arg_N(D), alignment)
1691 : : lhs. Handle linear by adding PHIs. */
1692 : 16164 : for (unsigned i = 0; i < node->simdclone->nargs; i++)
1693 : 11360 : if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1694 : 11360 : && (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg)
1695 : 1813 : || !is_gimple_reg_type
1696 : 1813 : (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1697 : : {
1698 : 174 : tree orig_arg = node->simdclone->args[i].orig_arg;
1699 : 174 : if (is_gimple_reg_type (TREE_TYPE (orig_arg)))
1700 : 144 : iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1701 : : else
1702 : : {
1703 : 30 : iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg));
1704 : 30 : gimple_add_tmp_var (iter1);
1705 : : }
1706 : 174 : gsi = gsi_after_labels (entry_bb);
1707 : 174 : g = gimple_build_assign (iter1, orig_arg);
1708 : 174 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1709 : 174 : gsi = gsi_after_labels (body_bb);
1710 : 174 : g = gimple_build_assign (orig_arg, iter1);
1711 : 174 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1712 : : }
1713 : 11186 : else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1714 : 1783 : && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg)
1715 : 292 : && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1716 : : == REFERENCE_TYPE
1717 : 11462 : && TREE_ADDRESSABLE
1718 : : (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1719 : : {
1720 : 68 : tree orig_arg = node->simdclone->args[i].orig_arg;
1721 : 68 : tree def = ssa_default_def (cfun, orig_arg);
1722 : 68 : if (def && !has_zero_uses (def))
1723 : : {
1724 : 68 : iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg)));
1725 : 68 : gimple_add_tmp_var (iter1);
1726 : 68 : gsi = gsi_after_labels (entry_bb);
1727 : 68 : g = gimple_build_assign (iter1, build_simple_mem_ref (def));
1728 : 68 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1729 : 68 : gsi = gsi_after_labels (body_bb);
1730 : 68 : g = gimple_build_assign (build_simple_mem_ref (def), iter1);
1731 : 68 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1732 : : }
1733 : : }
1734 : 11118 : else if (node->simdclone->args[i].alignment
1735 : 452 : && node->simdclone->args[i].arg_type
1736 : : == SIMD_CLONE_ARG_TYPE_UNIFORM
1737 : 240 : && (node->simdclone->args[i].alignment
1738 : 240 : & (node->simdclone->args[i].alignment - 1)) == 0
1739 : 11358 : && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1740 : : == POINTER_TYPE)
1741 : : {
1742 : 240 : unsigned int alignment = node->simdclone->args[i].alignment;
1743 : 240 : tree orig_arg = node->simdclone->args[i].orig_arg;
1744 : 240 : tree def = ssa_default_def (cfun, orig_arg);
1745 : 240 : if (def && !has_zero_uses (def))
1746 : : {
1747 : 232 : tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
1748 : 232 : gimple_seq seq = NULL;
1749 : 232 : bool need_cvt = false;
1750 : 232 : gcall *call
1751 : 232 : = gimple_build_call (fn, 2, def, size_int (alignment));
1752 : 232 : g = call;
1753 : 232 : if (!useless_type_conversion_p (TREE_TYPE (orig_arg),
1754 : : ptr_type_node))
1755 : 0 : need_cvt = true;
1756 : 232 : tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg);
1757 : 232 : gimple_call_set_lhs (g, t);
1758 : 232 : gimple_seq_add_stmt_without_update (&seq, g);
1759 : 232 : if (need_cvt)
1760 : : {
1761 : 0 : t = make_ssa_name (orig_arg);
1762 : 0 : g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g));
1763 : 0 : gimple_seq_add_stmt_without_update (&seq, g);
1764 : : }
1765 : 232 : gsi_insert_seq_on_edge_immediate
1766 : 232 : (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
1767 : :
1768 : 232 : entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1769 : 232 : node->create_edge (cgraph_node::get_create (fn),
1770 : : call, entry_bb->count);
1771 : :
1772 : 232 : imm_use_iterator iter;
1773 : 232 : use_operand_p use_p;
1774 : 232 : gimple *use_stmt;
1775 : 232 : tree repl = gimple_get_lhs (g);
1776 : 696 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1777 : 464 : if (is_gimple_debug (use_stmt) || use_stmt == call)
1778 : 232 : continue;
1779 : : else
1780 : 464 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1781 : 464 : SET_USE (use_p, repl);
1782 : : }
1783 : : }
1784 : 10878 : else if ((node->simdclone->args[i].arg_type
1785 : : == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
1786 : 9149 : || (node->simdclone->args[i].arg_type
1787 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
1788 : 8745 : || (node->simdclone->args[i].arg_type
1789 : : == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP)
1790 : 8605 : || (node->simdclone->args[i].arg_type
1791 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP))
1792 : : {
1793 : 2305 : tree orig_arg = node->simdclone->args[i].orig_arg;
1794 : 2305 : gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1795 : : || POINTER_TYPE_P (TREE_TYPE (orig_arg)));
1796 : 2305 : tree def = NULL_TREE;
1797 : 2305 : if (TREE_ADDRESSABLE (orig_arg))
1798 : : {
1799 : 132 : def = make_ssa_name (TREE_TYPE (orig_arg));
1800 : 132 : iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1801 : 132 : if (incr_bb)
1802 : 116 : iter2 = make_ssa_name (TREE_TYPE (orig_arg));
1803 : 132 : gsi = gsi_after_labels (entry_bb);
1804 : 132 : g = gimple_build_assign (def, orig_arg);
1805 : 132 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1806 : : }
1807 : : else
1808 : : {
1809 : 2173 : def = ssa_default_def (cfun, orig_arg);
1810 : 2173 : if (!def || has_zero_uses (def))
1811 : : def = NULL_TREE;
1812 : : else
1813 : : {
1814 : 2115 : iter1 = make_ssa_name (orig_arg);
1815 : 2115 : if (incr_bb)
1816 : 2083 : iter2 = make_ssa_name (orig_arg);
1817 : : }
1818 : : }
1819 : 2305 : if (def)
1820 : : {
1821 : 2247 : phi = create_phi_node (iter1, body_bb);
1822 : 2247 : add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
1823 : 2247 : if (incr_bb)
1824 : : {
1825 : 2199 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1826 : 4398 : enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1827 : 2199 : ? PLUS_EXPR : POINTER_PLUS_EXPR;
1828 : 4398 : tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1829 : 4398 : ? TREE_TYPE (orig_arg) : sizetype;
1830 : 2199 : tree addcst = simd_clone_linear_addend (node, i, addtype,
1831 : : entry_bb);
1832 : 2199 : gsi = gsi_last_bb (incr_bb);
1833 : 2199 : g = gimple_build_assign (iter2, code, iter1, addcst);
1834 : 2199 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1835 : : }
1836 : :
1837 : 2247 : imm_use_iterator iter;
1838 : 2247 : use_operand_p use_p;
1839 : 2247 : gimple *use_stmt;
1840 : 2247 : if (TREE_ADDRESSABLE (orig_arg))
1841 : : {
1842 : 132 : gsi = gsi_after_labels (body_bb);
1843 : 132 : g = gimple_build_assign (orig_arg, iter1);
1844 : 132 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1845 : : }
1846 : : else
1847 : 6653 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1848 : 4538 : if (use_stmt == phi)
1849 : 2115 : continue;
1850 : : else
1851 : 4846 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1852 : 4538 : SET_USE (use_p, iter1);
1853 : : }
1854 : : }
1855 : 8573 : else if (node->simdclone->args[i].arg_type
1856 : : == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP
1857 : 8573 : || (node->simdclone->args[i].arg_type
1858 : : == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP))
1859 : : {
1860 : 224 : tree orig_arg = node->simdclone->args[i].orig_arg;
1861 : 224 : tree def = ssa_default_def (cfun, orig_arg);
1862 : 224 : gcc_assert (!TREE_ADDRESSABLE (orig_arg)
1863 : : && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE);
1864 : 224 : if (def && !has_zero_uses (def))
1865 : : {
1866 : 224 : tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
1867 : 224 : iter1 = make_ssa_name (orig_arg);
1868 : 224 : if (incr_bb)
1869 : 208 : iter2 = make_ssa_name (orig_arg);
1870 : 224 : tree iter3 = make_ssa_name (rtype);
1871 : 224 : tree iter4 = make_ssa_name (rtype);
1872 : 224 : tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
1873 : 224 : gsi = gsi_after_labels (entry_bb);
1874 : 224 : gimple *load
1875 : 224 : = gimple_build_assign (iter3, build_simple_mem_ref (def));
1876 : 224 : gsi_insert_before (&gsi, load, GSI_NEW_STMT);
1877 : :
1878 : 224 : tree array = node->simdclone->args[i].simd_array;
1879 : 224 : TREE_ADDRESSABLE (array) = 1;
1880 : 224 : tree ptr = build_fold_addr_expr (array);
1881 : 224 : phi = create_phi_node (iter1, body_bb);
1882 : 224 : add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
1883 : 224 : if (incr_bb)
1884 : : {
1885 : 208 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1886 : 208 : g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
1887 : 208 : TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
1888 : 208 : gsi = gsi_last_bb (incr_bb);
1889 : 208 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1890 : : }
1891 : :
1892 : 224 : phi = create_phi_node (iter4, body_bb);
1893 : 224 : add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
1894 : 224 : if (incr_bb)
1895 : : {
1896 : 208 : add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
1897 : 416 : enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1898 : 208 : ? PLUS_EXPR : POINTER_PLUS_EXPR;
1899 : 416 : tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1900 : 416 : ? TREE_TYPE (iter3) : sizetype;
1901 : 208 : tree addcst = simd_clone_linear_addend (node, i, addtype,
1902 : : entry_bb);
1903 : 208 : g = gimple_build_assign (iter5, code, iter4, addcst);
1904 : 208 : gsi = gsi_last_bb (incr_bb);
1905 : 208 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1906 : : }
1907 : :
1908 : 224 : g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
1909 : 224 : gsi = gsi_after_labels (body_bb);
1910 : 224 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1911 : :
1912 : 224 : imm_use_iterator iter;
1913 : 224 : use_operand_p use_p;
1914 : 224 : gimple *use_stmt;
1915 : 880 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1916 : 656 : if (use_stmt == load)
1917 : 224 : continue;
1918 : : else
1919 : 864 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1920 : 656 : SET_USE (use_p, iter1);
1921 : :
1922 : 224 : if (!TYPE_READONLY (rtype) && incr_bb)
1923 : : {
1924 : 144 : tree v = make_ssa_name (rtype);
1925 : 144 : tree aref = build4 (ARRAY_REF, rtype, array,
1926 : : size_zero_node, NULL_TREE,
1927 : : NULL_TREE);
1928 : 144 : gsi = gsi_after_labels (new_exit_bb);
1929 : 144 : g = gimple_build_assign (v, aref);
1930 : 144 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1931 : 144 : g = gimple_build_assign (build_simple_mem_ref (def), v);
1932 : 144 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1933 : : }
1934 : : }
1935 : : }
1936 : :
1937 : 4804 : calculate_dominance_info (CDI_DOMINATORS);
1938 : 4804 : if (loop)
1939 : 4736 : add_loop (loop, loop->header->loop_father);
1940 : 4804 : update_ssa (TODO_update_ssa);
1941 : :
1942 : 4804 : pop_cfun ();
1943 : 4804 : }
1944 : :
1945 : : /* If the function in NODE is tagged as an elemental SIMD function,
1946 : : create the appropriate SIMD clones. */
1947 : :
1948 : : void
1949 : 4251823 : expand_simd_clones (struct cgraph_node *node)
1950 : : {
1951 : 4251823 : tree attr;
1952 : 4251823 : bool explicit_p = true;
1953 : :
1954 : 4251823 : if (node->inlined_to
1955 : 4251823 : || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
1956 : 1226804 : return;
1957 : :
1958 : 3025019 : attr = lookup_attribute ("omp declare simd",
1959 : 3025019 : DECL_ATTRIBUTES (node->decl));
1960 : :
1961 : : /* See if we can add an "omp declare simd" directive implicitly
1962 : : before giving up. */
1963 : : /* FIXME: OpenACC "#pragma acc routine" translates into
1964 : : "omp declare target", but appears also to have some other effects
1965 : : that conflict with generating SIMD clones, causing ICEs. So don't
1966 : : do this if we've got OpenACC instead of OpenMP. */
1967 : 3025019 : if (attr == NULL_TREE
1968 : : #ifdef ACCEL_COMPILER
1969 : : && (flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_ANY
1970 : : || flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_NOHOST)
1971 : : #else
1972 : 3023686 : && (flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_ANY
1973 : 3023602 : || flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_HOST)
1974 : : #endif
1975 : 84 : && !oacc_get_fn_attrib (node->decl)
1976 : 3025103 : && ok_for_auto_simd_clone (node))
1977 : : {
1978 : 5 : attr = tree_cons (get_identifier ("omp declare simd"), NULL,
1979 : 5 : DECL_ATTRIBUTES (node->decl));
1980 : 5 : DECL_ATTRIBUTES (node->decl) = attr;
1981 : 5 : explicit_p = false;
1982 : : }
1983 : :
1984 : 3025019 : if (attr == NULL_TREE)
1985 : : return;
1986 : :
1987 : : /* Ignore
1988 : : #pragma omp declare simd
1989 : : extern int foo ();
1990 : : in C, there we don't know the argument types at all. */
1991 : 1338 : if (!node->definition
1992 : 1338 : && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE)
1993 : : return;
1994 : :
1995 : : /* Call this before creating clone_info, as it might ggc_collect. */
1996 : 1338 : if (node->definition && node->has_gimple_body_p ())
1997 : 718 : node->get_body ();
1998 : :
1999 : 1566 : do
2000 : : {
2001 : : /* Start with parsing the "omp declare simd" attribute(s). */
2002 : 1566 : bool inbranch_clause_specified;
2003 : 1566 : struct cgraph_simd_clone *clone_info
2004 : 1566 : = simd_clone_clauses_extract (node, TREE_VALUE (attr),
2005 : : &inbranch_clause_specified);
2006 : 1566 : if (clone_info == NULL)
2007 : 8 : continue;
2008 : :
2009 : 1565 : poly_uint64 orig_simdlen = clone_info->simdlen;
2010 : 1565 : tree base_type = simd_clone_compute_base_data_type (node, clone_info);
2011 : :
2012 : : /* The target can return 0 (no simd clones should be created),
2013 : : 1 (just one ISA of simd clones should be created) or higher
2014 : : count of ISA variants. In that case, clone_info is initialized
2015 : : for the first ISA variant. */
2016 : 1565 : int count
2017 : 1565 : = targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info,
2018 : : base_type, 0,
2019 : : explicit_p);
2020 : 1565 : if (count == 0)
2021 : 7 : continue;
2022 : :
2023 : : /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED,
2024 : : also create one inbranch and one !inbranch clone of it. */
2025 : 13578 : for (int i = 0; i < count * 2; i++)
2026 : : {
2027 : 12020 : struct cgraph_simd_clone *clone = clone_info;
2028 : 12020 : if (inbranch_clause_specified && (i & 1) != 0)
2029 : 3950 : continue;
2030 : :
2031 : 8070 : if (i != 0)
2032 : : {
2033 : 13024 : clone = simd_clone_struct_alloc (clone_info->nargs
2034 : 6512 : + ((i & 1) != 0));
2035 : 6512 : simd_clone_struct_copy (clone, clone_info);
2036 : : /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen
2037 : : and simd_clone_adjust_argument_types did to the first
2038 : : clone's info. */
2039 : 6512 : clone->nargs -= clone_info->inbranch;
2040 : 6512 : clone->simdlen = orig_simdlen;
2041 : : /* And call the target hook again to get the right ISA. */
2042 : 6512 : targetm.simd_clone.compute_vecsize_and_simdlen (node, clone,
2043 : : base_type,
2044 : : i / 2,
2045 : : explicit_p);
2046 : 6512 : if ((i & 1) != 0)
2047 : 2060 : clone->inbranch = 1;
2048 : : }
2049 : :
2050 : : /* simd_clone_mangle might fail if such a clone has been created
2051 : : already. */
2052 : 8070 : tree id = simd_clone_mangle (node, clone);
2053 : 8070 : if (id == NULL_TREE)
2054 : : {
2055 : 498 : if (i == 0)
2056 : 93 : clone->nargs += clone->inbranch;
2057 : 498 : continue;
2058 : : }
2059 : :
2060 : : /* Only when we are sure we want to create the clone actually
2061 : : clone the function (or definitions) or create another
2062 : : extern FUNCTION_DECL (for prototypes without definitions). */
2063 : 7572 : struct cgraph_node *n = simd_clone_create (node, !explicit_p);
2064 : 7572 : if (n == NULL)
2065 : : {
2066 : 0 : if (i == 0)
2067 : 0 : clone->nargs += clone->inbranch;
2068 : 0 : continue;
2069 : : }
2070 : :
2071 : 7572 : n->simdclone = clone;
2072 : 7572 : clone->origin = node;
2073 : 7572 : clone->next_clone = NULL;
2074 : 7572 : if (node->simd_clones == NULL)
2075 : : {
2076 : 1330 : clone->prev_clone = n;
2077 : 1330 : node->simd_clones = n;
2078 : : }
2079 : : else
2080 : : {
2081 : 6242 : clone->prev_clone = node->simd_clones->simdclone->prev_clone;
2082 : 6242 : clone->prev_clone->simdclone->next_clone = n;
2083 : 6242 : node->simd_clones->simdclone->prev_clone = n;
2084 : : }
2085 : 7572 : symtab->change_decl_assembler_name (n->decl, id);
2086 : : /* And finally adjust the return type, parameters and for
2087 : : definitions also function body. */
2088 : 7572 : if (node->definition)
2089 : 4804 : simd_clone_adjust (n);
2090 : : else
2091 : : {
2092 : 2768 : TREE_TYPE (n->decl)
2093 : 2768 : = build_distinct_type_copy (TREE_TYPE (n->decl));
2094 : 2768 : simd_clone_adjust_return_type (n);
2095 : 2768 : simd_clone_adjust_argument_types (n);
2096 : 2768 : targetm.simd_clone.adjust (n);
2097 : : }
2098 : 7572 : if (dump_file)
2099 : 10 : fprintf (dump_file, "\nGenerated %s clone %s\n",
2100 : 10 : (TREE_PUBLIC (n->decl) ? "global" : "local"),
2101 : 10 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
2102 : : }
2103 : : }
2104 : 1566 : while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
2105 : : }
2106 : :
2107 : : /* Entry point for IPA simd clone creation pass. */
2108 : :
2109 : : static unsigned int
2110 : 229616 : ipa_omp_simd_clone (void)
2111 : : {
2112 : 229616 : struct cgraph_node *node;
2113 : 8962874 : FOR_EACH_FUNCTION (node)
2114 : 4251821 : expand_simd_clones (node);
2115 : 229616 : return 0;
2116 : : }
2117 : :
2118 : : namespace {
2119 : :
2120 : : const pass_data pass_data_omp_simd_clone =
2121 : : {
2122 : : SIMPLE_IPA_PASS, /* type */
2123 : : "simdclone", /* name */
2124 : : OPTGROUP_OMP, /* optinfo_flags */
2125 : : TV_NONE, /* tv_id */
2126 : : ( PROP_ssa | PROP_cfg ), /* properties_required */
2127 : : 0, /* properties_provided */
2128 : : 0, /* properties_destroyed */
2129 : : 0, /* todo_flags_start */
2130 : : 0, /* todo_flags_finish */
2131 : : };
2132 : :
2133 : : class pass_omp_simd_clone : public simple_ipa_opt_pass
2134 : : {
2135 : : public:
2136 : 285617 : pass_omp_simd_clone(gcc::context *ctxt)
2137 : 571234 : : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt)
2138 : : {}
2139 : :
2140 : : /* opt_pass methods: */
2141 : : bool gate (function *) final override;
2142 : 229616 : unsigned int execute (function *) final override
2143 : : {
2144 : 229616 : return ipa_omp_simd_clone ();
2145 : : }
2146 : : };
2147 : :
2148 : : bool
2149 : 229622 : pass_omp_simd_clone::gate (function *)
2150 : : {
2151 : 229622 : return targetm.simd_clone.compute_vecsize_and_simdlen != NULL;
2152 : : }
2153 : :
2154 : : } // anon namespace
2155 : :
2156 : : simple_ipa_opt_pass *
2157 : 285617 : make_pass_omp_simd_clone (gcc::context *ctxt)
2158 : : {
2159 : 285617 : return new pass_omp_simd_clone (ctxt);
2160 : : }
|