Branch data Line data Source code
1 : : /* OMP constructs' SIMD clone supporting code.
2 : :
3 : : Copyright (C) 2005-2025 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 : 67 : auto_simd_fail (tree decl, const char *excuse)
61 : : {
62 : 67 : if (dump_file && (dump_flags & TDF_DETAILS))
63 : 134 : fprintf (dump_file, "\nNot auto-cloning %s because %s\n",
64 : 67 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
65 : : excuse);
66 : 67 : 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 : 17 : auto_simd_check_stmt (gimple *stmt, tree outer)
80 : : {
81 : 17 : tree decl;
82 : :
83 : 17 : switch (gimple_code (stmt))
84 : : {
85 : 4 : 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 : 4 : if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))
91 : : break;
92 : 4 : if (gimple_call_internal_p (stmt))
93 : 0 : return auto_simd_fail (outer,
94 : 0 : "body contains internal function call");
95 : :
96 : 4 : decl = gimple_call_fndecl (stmt);
97 : :
98 : : /* We can't know whether indirect calls are safe. */
99 : 4 : 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 : 4 : if (lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (decl)))
105 : : break;
106 : :
107 : : /* Let recursive calls to the current function through. */
108 : 4 : 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 : 4 : 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 : 13 : if (gimple_store_p (stmt))
138 : 1 : return auto_simd_fail (outer, "body includes memory write");
139 : :
140 : : /* Volatile reads are not permitted. */
141 : 21 : 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 : 42 : plausible_type_for_simd_clone (tree t)
152 : : {
153 : 42 : if (VOID_TYPE_P (t))
154 : : return true;
155 : 32 : 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 : 31 : 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 : 71 : ok_for_auto_simd_clone (struct cgraph_node *node)
171 : : {
172 : 71 : tree decl = node->decl;
173 : 71 : tree t;
174 : 71 : basic_block bb;
175 : :
176 : : /* Nothing to do if the function isn't a definition or doesn't
177 : : have a body. */
178 : 71 : if (!node->definition || !node->has_gimple_body_p ())
179 : 46 : 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 : 25 : if (!node->callers)
184 : 13 : 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 : 12 : if (lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (decl))
189 : 12 : || lookup_attribute ("noclone", DECL_ATTRIBUTES (decl))
190 : 24 : || !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 : 12 : tree host = lookup_attribute ("omp declare target host",
200 : 12 : DECL_ATTRIBUTES (decl));
201 : 12 : tree nohost = lookup_attribute ("omp declare target nohost",
202 : 12 : 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 : 12 : 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 : 11 : t = TREE_TYPE (TREE_TYPE (decl));
215 : 11 : if (!plausible_type_for_simd_clone (t))
216 : 0 : return auto_simd_fail (decl, "return type fails sniff test");
217 : :
218 : 11 : if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
219 : : {
220 : 11 : for (tree temp = TYPE_ARG_TYPES (TREE_TYPE (decl));
221 : 41 : temp; temp = TREE_CHAIN (temp))
222 : : {
223 : 31 : t = TREE_VALUE (temp);
224 : 31 : 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 : 10 : node->get_body ();
242 : :
243 : 17 : FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (decl))
244 : : {
245 : 37 : for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
246 : 11 : gsi_next (&gsi))
247 : 17 : if (!auto_simd_check_stmt (gsi_stmt (gsi), decl))
248 : 67 : return false;
249 : : }
250 : :
251 : : /* All is good. */
252 : 4 : if (dump_file)
253 : 8 : fprintf (dump_file, "\nMarking %s for auto-cloning\n",
254 : 4 : 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 : 7578 : simd_clone_struct_alloc (int nargs)
263 : : {
264 : 7578 : struct cgraph_simd_clone *clone_info;
265 : 7578 : size_t len = (sizeof (struct cgraph_simd_clone)
266 : 7578 : + nargs * sizeof (struct cgraph_simd_clone_arg));
267 : 7578 : clone_info = (struct cgraph_simd_clone *)
268 : 7578 : ggc_internal_cleared_alloc (len);
269 : 7578 : 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 : 6103 : simd_clone_struct_copy (struct cgraph_simd_clone *to,
276 : : struct cgraph_simd_clone *from)
277 : : {
278 : 6103 : memcpy (to, from, (sizeof (struct cgraph_simd_clone)
279 : 6103 : + ((from->nargs - from->inbranch)
280 : 6103 : * sizeof (struct cgraph_simd_clone_arg))));
281 : 6103 : }
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 : 4750 : simd_clone_vector_of_formal_parm_types (vec<tree> *args, tree fndecl)
289 : : {
290 : 4750 : if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
291 : : {
292 : 4706 : push_function_arg_types (args, TREE_TYPE (fndecl));
293 : 4706 : return;
294 : : }
295 : 44 : push_function_arg_decls (args, fndecl);
296 : 44 : unsigned int i;
297 : 44 : tree arg;
298 : 93 : 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 : 1475 : simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
310 : : bool *inbranch_specified)
311 : : {
312 : 1475 : auto_vec<tree> args;
313 : 1475 : simd_clone_vector_of_formal_parm_types (&args, node->decl);
314 : 1475 : tree t;
315 : 1475 : int n;
316 : 1475 : *inbranch_specified = false;
317 : :
318 : 1475 : n = args.length ();
319 : 2938 : if (n > 0 && args.last () == void_type_node)
320 : 1467 : 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 : 1475 : struct cgraph_simd_clone *clone_info = simd_clone_struct_alloc (n + 1);
325 : 1475 : clone_info->nargs = n;
326 : :
327 : 1475 : if (!clauses)
328 : 170 : goto out;
329 : :
330 : 1305 : clauses = TREE_VALUE (clauses);
331 : 1305 : if (!clauses || TREE_CODE (clauses) != OMP_CLAUSE)
332 : 99 : goto out;
333 : :
334 : 3349 : for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t))
335 : : {
336 : 2143 : switch (OMP_CLAUSE_CODE (t))
337 : : {
338 : 104 : case OMP_CLAUSE_INBRANCH:
339 : 104 : clone_info->inbranch = 1;
340 : 104 : *inbranch_specified = true;
341 : 104 : break;
342 : 852 : case OMP_CLAUSE_NOTINBRANCH:
343 : 852 : clone_info->inbranch = 0;
344 : 852 : *inbranch_specified = true;
345 : 852 : break;
346 : 239 : case OMP_CLAUSE_SIMDLEN:
347 : 239 : clone_info->simdlen
348 : 239 : = TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
349 : 239 : break;
350 : 491 : case OMP_CLAUSE_LINEAR:
351 : 491 : {
352 : 491 : tree decl = OMP_CLAUSE_DECL (t);
353 : 491 : tree step = OMP_CLAUSE_LINEAR_STEP (t);
354 : 491 : int argno = TREE_INT_CST_LOW (decl);
355 : 491 : if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (t))
356 : : {
357 : 31 : enum cgraph_simd_clone_arg_type arg_type;
358 : 31 : if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
359 : 11 : 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 : 31 : clone_info->args[argno].arg_type = arg_type;
380 : 31 : clone_info->args[argno].linear_step = tree_to_shwi (step);
381 : 31 : gcc_assert (clone_info->args[argno].linear_step >= 0
382 : : && clone_info->args[argno].linear_step < n);
383 : : }
384 : : else
385 : : {
386 : 460 : if (POINTER_TYPE_P (args[argno]))
387 : 176 : step = fold_convert (ssizetype, step);
388 : 460 : 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 : 460 : 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 : 460 : enum cgraph_simd_clone_arg_type arg_type;
403 : 460 : if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
404 : 113 : 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 : 460 : clone_info->args[argno].arg_type = arg_type;
425 : 460 : clone_info->args[argno].linear_step = tree_to_shwi (step);
426 : : }
427 : : }
428 : : break;
429 : : }
430 : 373 : case OMP_CLAUSE_UNIFORM:
431 : 373 : {
432 : 373 : tree decl = OMP_CLAUSE_DECL (t);
433 : 373 : int argno = tree_to_uhwi (decl);
434 : 373 : clone_info->args[argno].arg_type
435 : 373 : = SIMD_CLONE_ARG_TYPE_UNIFORM;
436 : 373 : break;
437 : : }
438 : 84 : case OMP_CLAUSE_ALIGNED:
439 : 84 : {
440 : : /* Ignore aligned (x) for declare simd, for the ABI we really
441 : : need an alignment specified. */
442 : 84 : if (OMP_CLAUSE_ALIGNED_ALIGNMENT (t) == NULL_TREE)
443 : : break;
444 : 80 : tree decl = OMP_CLAUSE_DECL (t);
445 : 80 : int argno = tree_to_uhwi (decl);
446 : 80 : clone_info->args[argno].alignment
447 : 80 : = TREE_INT_CST_LOW (OMP_CLAUSE_ALIGNED_ALIGNMENT (t));
448 : 80 : break;
449 : : }
450 : : default:
451 : : break;
452 : : }
453 : : }
454 : :
455 : 1206 : out:
456 : 1475 : 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 : 3982 : for (unsigned int argno = 0; argno < clone_info->nargs; argno++)
465 : 2508 : if (TYPE_ATOMIC (args[argno])
466 : 2508 : && 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 : 1475 : }
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 : 4141 : simd_clone_compute_base_data_type (struct cgraph_node *node,
484 : : struct cgraph_simd_clone *clone_info)
485 : : {
486 : 4141 : tree type = integer_type_node;
487 : 4141 : tree fndecl = node->decl;
488 : :
489 : : /* a) For non-void function, the characteristic data type is the
490 : : return type. */
491 : 4141 : if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE)
492 : 3590 : 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 : 551 : auto_vec<tree> map;
500 : 551 : simd_clone_vector_of_formal_parm_types (&map, fndecl);
501 : 738 : for (unsigned int i = 0; i < clone_info->nargs; ++i)
502 : 362 : if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
503 : : {
504 : 175 : type = map[i];
505 : 175 : break;
506 : : }
507 : 551 : }
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 : 4141 : if (RECORD_OR_UNION_TYPE_P (type)
514 : 2 : && !aggregate_value_p (type, NULL)
515 : 4143 : && 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 : 7570 : simd_clone_mangle (struct cgraph_node *node,
531 : : struct cgraph_simd_clone *clone_info)
532 : : {
533 : 7570 : char vecsize_mangle = clone_info->vecsize_mangle;
534 : 7570 : char mask = clone_info->inbranch ? 'M' : 'N';
535 : 7570 : poly_uint64 simdlen = clone_info->simdlen;
536 : 7570 : unsigned int n;
537 : 7570 : pretty_printer pp;
538 : :
539 : 7570 : gcc_assert (vecsize_mangle && maybe_ne (simdlen, 0U));
540 : :
541 : 7570 : pp_string (&pp, "_ZGV");
542 : 7570 : pp_character (&pp, vecsize_mangle);
543 : 7570 : pp_character (&pp, mask);
544 : :
545 : 7570 : unsigned HOST_WIDE_INT len;
546 : 7570 : if (simdlen.is_constant (&len))
547 : 7570 : pp_decimal_int (&pp, (int) (len));
548 : : else
549 : : pp_character (&pp, 'x');
550 : :
551 : 20397 : for (n = 0; n < clone_info->nargs; ++n)
552 : : {
553 : 12827 : struct cgraph_simd_clone_arg arg = clone_info->args[n];
554 : :
555 : 12827 : switch (arg.arg_type)
556 : : {
557 : 2083 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
558 : 2083 : pp_character (&pp, 'u');
559 : 2083 : break;
560 : 1935 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
561 : 1935 : pp_character (&pp, 'l');
562 : 1935 : goto mangle_linear;
563 : 332 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
564 : 332 : pp_character (&pp, 'R');
565 : 332 : goto mangle_linear;
566 : 160 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
567 : 160 : pp_character (&pp, 'L');
568 : 160 : goto mangle_linear;
569 : 160 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
570 : 160 : pp_character (&pp, 'U');
571 : 160 : goto mangle_linear;
572 : 2587 : mangle_linear:
573 : 2587 : gcc_assert (arg.linear_step != 0);
574 : 2587 : if (arg.linear_step > 1)
575 : 1242 : pp_unsigned_wide_integer (&pp, arg.linear_step);
576 : 1345 : else if (arg.linear_step < 0)
577 : : {
578 : 73 : pp_character (&pp, 'n');
579 : 73 : pp_unsigned_wide_integer (&pp, (-(unsigned HOST_WIDE_INT)
580 : : arg.linear_step));
581 : : }
582 : : break;
583 : 112 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
584 : 112 : pp_string (&pp, "ls");
585 : 112 : pp_unsigned_wide_integer (&pp, arg.linear_step);
586 : 112 : break;
587 : 28 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
588 : 28 : pp_string (&pp, "Rs");
589 : 28 : pp_unsigned_wide_integer (&pp, arg.linear_step);
590 : 28 : break;
591 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
592 : 12 : pp_string (&pp, "Ls");
593 : 12 : pp_unsigned_wide_integer (&pp, arg.linear_step);
594 : 12 : break;
595 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
596 : 12 : pp_string (&pp, "Us");
597 : 12 : pp_unsigned_wide_integer (&pp, arg.linear_step);
598 : 12 : break;
599 : 7993 : default:
600 : 7993 : pp_character (&pp, 'v');
601 : : }
602 : 12827 : if (arg.alignment)
603 : : {
604 : 520 : pp_character (&pp, 'a');
605 : 520 : pp_decimal_int (&pp, arg.alignment);
606 : : }
607 : : }
608 : :
609 : 7570 : pp_underscore (&pp);
610 : 7570 : const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
611 : 7570 : if (*str == '*')
612 : 16 : ++str;
613 : 7570 : pp_string (&pp, str);
614 : 7570 : str = pp_formatted_text (&pp);
615 : :
616 : : /* If there already is a SIMD clone with the same mangled name, don't
617 : : add another one. This can happen e.g. for
618 : : #pragma omp declare simd
619 : : #pragma omp declare simd simdlen(8)
620 : : int foo (int, int);
621 : : if the simdlen is assumed to be 8 for the first one, etc. */
622 : 31350 : for (struct cgraph_node *clone = node->simd_clones; clone;
623 : 23780 : clone = clone->simdclone->next_clone)
624 : 24174 : if (id_equal (DECL_ASSEMBLER_NAME (clone->decl), str))
625 : : return NULL_TREE;
626 : :
627 : 7176 : return get_identifier (str);
628 : 7570 : }
629 : :
630 : : /* Create a simd clone of OLD_NODE and return it. If FORCE_LOCAL is true,
631 : : create it as a local symbol, otherwise copy the symbol linkage and
632 : : visibility attributes from OLD_NODE. */
633 : :
634 : : static struct cgraph_node *
635 : 7176 : simd_clone_create (struct cgraph_node *old_node, bool force_local)
636 : : {
637 : 7176 : struct cgraph_node *new_node;
638 : 7176 : if (old_node->definition)
639 : : {
640 : 4452 : if (!old_node->has_gimple_body_p ())
641 : : return NULL;
642 : 4452 : old_node->get_body ();
643 : 4452 : new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL,
644 : : NULL, NULL,
645 : : "simdclone");
646 : : }
647 : : else
648 : : {
649 : 2724 : tree old_decl = old_node->decl;
650 : 2724 : tree new_decl = copy_node (old_node->decl);
651 : 2724 : DECL_NAME (new_decl) = clone_function_name_numbered (old_decl,
652 : : "simdclone");
653 : 2724 : SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
654 : 2724 : SET_DECL_RTL (new_decl, NULL);
655 : 2724 : DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
656 : 2724 : DECL_STATIC_DESTRUCTOR (new_decl) = 0;
657 : 2724 : new_node = old_node->create_version_clone (new_decl, vNULL, NULL);
658 : 2724 : if (old_node->in_other_partition)
659 : 16 : new_node->in_other_partition = 1;
660 : : }
661 : 7176 : if (new_node == NULL)
662 : : return new_node;
663 : :
664 : 7176 : set_decl_built_in_function (new_node->decl, NOT_BUILT_IN, 0);
665 : 7176 : if (force_local)
666 : : {
667 : 8 : TREE_PUBLIC (new_node->decl) = 0;
668 : 8 : DECL_COMDAT (new_node->decl) = 0;
669 : 8 : DECL_WEAK (new_node->decl) = 0;
670 : 8 : DECL_EXTERNAL (new_node->decl) = 0;
671 : 8 : DECL_VISIBILITY_SPECIFIED (new_node->decl) = 0;
672 : 8 : DECL_VISIBILITY (new_node->decl) = VISIBILITY_DEFAULT;
673 : 8 : DECL_DLLIMPORT_P (new_node->decl) = 0;
674 : : }
675 : : else
676 : : {
677 : 7168 : TREE_PUBLIC (new_node->decl) = TREE_PUBLIC (old_node->decl);
678 : 7168 : DECL_COMDAT (new_node->decl) = DECL_COMDAT (old_node->decl);
679 : 7168 : DECL_WEAK (new_node->decl) = DECL_WEAK (old_node->decl);
680 : 7168 : DECL_EXTERNAL (new_node->decl) = DECL_EXTERNAL (old_node->decl);
681 : 7168 : DECL_VISIBILITY_SPECIFIED (new_node->decl)
682 : 7168 : = DECL_VISIBILITY_SPECIFIED (old_node->decl);
683 : 7168 : DECL_VISIBILITY (new_node->decl) = DECL_VISIBILITY (old_node->decl);
684 : 7168 : DECL_DLLIMPORT_P (new_node->decl) = DECL_DLLIMPORT_P (old_node->decl);
685 : 7168 : if (DECL_ONE_ONLY (old_node->decl))
686 : 300 : make_decl_one_only (new_node->decl,
687 : : DECL_ASSEMBLER_NAME (new_node->decl));
688 : :
689 : : /* The method cgraph_version_clone_with_body () will force the new
690 : : symbol local. Undo this, and inherit external visibility from
691 : : the old node. */
692 : 7168 : new_node->local = old_node->local;
693 : 7168 : new_node->externally_visible = old_node->externally_visible;
694 : 7168 : new_node->has_omp_variant_constructs
695 : 7168 : = old_node->has_omp_variant_constructs;
696 : : }
697 : :
698 : : /* Mark clones with internal linkage as gc'able, so they will not be
699 : : emitted unless the vectorizer can actually use them. */
700 : 7176 : if (!TREE_PUBLIC (new_node->decl))
701 : 112 : new_node->gc_candidate = true;
702 : :
703 : : return new_node;
704 : : }
705 : :
706 : : /* Adjust the return type of the given function to its appropriate
707 : : vector counterpart. */
708 : :
709 : : static void
710 : 7176 : simd_clone_adjust_return_type (struct cgraph_node *node)
711 : : {
712 : 7176 : tree fndecl = node->decl;
713 : 7176 : tree orig_rettype = TREE_TYPE (TREE_TYPE (fndecl));
714 : 7176 : poly_uint64 veclen;
715 : 7176 : tree t;
716 : :
717 : : /* Adjust the function return type. */
718 : 7176 : if (orig_rettype == void_type_node)
719 : 752 : return;
720 : 6424 : t = TREE_TYPE (TREE_TYPE (fndecl));
721 : 6424 : if (INTEGRAL_TYPE_P (t) || POINTER_TYPE_P (t))
722 : 3067 : veclen = node->simdclone->vecsize_int;
723 : : else
724 : 3357 : veclen = node->simdclone->vecsize_float;
725 : 6424 : if (known_eq (veclen, 0U))
726 : 0 : veclen = node->simdclone->simdlen;
727 : : else
728 : 12848 : veclen = exact_div (veclen, GET_MODE_BITSIZE (SCALAR_TYPE_MODE (t)));
729 : 6424 : if (multiple_p (veclen, node->simdclone->simdlen))
730 : 6202 : veclen = node->simdclone->simdlen;
731 : 6424 : if (POINTER_TYPE_P (t))
732 : 18 : t = pointer_sized_int_node;
733 : 6424 : if (known_eq (veclen, node->simdclone->simdlen))
734 : 6202 : t = build_vector_type (t, node->simdclone->simdlen);
735 : : else
736 : : {
737 : 222 : t = build_vector_type (t, veclen);
738 : 222 : t = build_array_type_nelts (t, exact_div (node->simdclone->simdlen,
739 : : veclen));
740 : : }
741 : 6424 : TREE_TYPE (TREE_TYPE (fndecl)) = t;
742 : : }
743 : :
744 : : /* Each vector argument has a corresponding array to be used locally
745 : : as part of the eventual loop. Create such temporary array and
746 : : return it.
747 : :
748 : : PREFIX is the prefix to be used for the temporary.
749 : :
750 : : TYPE is the inner element type.
751 : :
752 : : SIMDLEN is the number of elements. */
753 : :
754 : : static tree
755 : 6083 : create_tmp_simd_array (const char *prefix, tree type, poly_uint64 simdlen)
756 : : {
757 : 6083 : tree atype = build_array_type_nelts (type, simdlen);
758 : 6083 : tree avar = create_tmp_var_raw (atype, prefix);
759 : 6083 : gimple_add_tmp_var (avar);
760 : 6083 : return avar;
761 : : }
762 : :
763 : : /* Modify the function argument types to their corresponding vector
764 : : counterparts if appropriate. Also, create one array for each simd
765 : : argument to be used locally when using the function arguments as
766 : : part of the loop.
767 : :
768 : : NODE is the function whose arguments are to be adjusted.
769 : :
770 : : If NODE does not represent function definition, returns NULL. Otherwise
771 : : returns an adjustment class that will be filled describing how the argument
772 : : declarations will be remapped. New arguments which are not to be remapped
773 : : are marked with USER_FLAG. */
774 : :
775 : : static void
776 : 7176 : simd_clone_adjust_argument_types (struct cgraph_node *node)
777 : : {
778 : 7176 : auto_vec<tree> args;
779 : :
780 : 7176 : if (node->definition)
781 : 4452 : push_function_arg_decls (&args, node->decl);
782 : : else
783 : 2724 : simd_clone_vector_of_formal_parm_types (&args, node->decl);
784 : 7176 : struct cgraph_simd_clone *sc = node->simdclone;
785 : 7176 : unsigned i, k;
786 : 7176 : poly_uint64 veclen;
787 : 7176 : auto_vec<tree> new_params;
788 : :
789 : 19349 : for (i = 0; i < sc->nargs; ++i)
790 : : {
791 : 12173 : tree parm = NULL_TREE;
792 : 12173 : tree parm_type = NULL_TREE;
793 : 12173 : if (i < args.length())
794 : : {
795 : 12173 : parm = args[i];
796 : 12173 : parm_type = node->definition ? TREE_TYPE (parm) : parm;
797 : : }
798 : :
799 : 12173 : sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
800 : 12173 : sc->args[i].orig_type = parm_type;
801 : :
802 : 12173 : switch (sc->args[i].arg_type)
803 : : {
804 : 4178 : default:
805 : 4178 : new_params.safe_push (parm_type);
806 : 8528 : break;
807 : 172 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
808 : 172 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
809 : 172 : new_params.safe_push (parm_type);
810 : 172 : if (node->definition)
811 : 172 : sc->args[i].simd_array
812 : 172 : = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
813 : 172 : TREE_TYPE (parm_type),
814 : : sc->simdlen);
815 : : break;
816 : 7823 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
817 : 7823 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
818 : 7823 : case SIMD_CLONE_ARG_TYPE_VECTOR:
819 : 7823 : if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type))
820 : 3613 : veclen = sc->vecsize_int;
821 : : else
822 : 4210 : veclen = sc->vecsize_float;
823 : 7823 : if (known_eq (veclen, 0U))
824 : 0 : veclen = sc->simdlen;
825 : : else
826 : 7823 : veclen
827 : 7823 : = exact_div (veclen,
828 : 15646 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type)));
829 : 7823 : if (multiple_p (veclen, sc->simdlen))
830 : 6297 : veclen = sc->simdlen;
831 : 7823 : tree vtype;
832 : 7823 : if (POINTER_TYPE_P (parm_type))
833 : 842 : vtype = build_vector_type (pointer_sized_int_node, veclen);
834 : : else
835 : 6981 : vtype = build_vector_type (parm_type, veclen);
836 : 7823 : sc->args[i].vector_type = vtype;
837 : 7823 : k = vector_unroll_factor (sc->simdlen, veclen);
838 : 17630 : for (unsigned j = 0; j < k; j++)
839 : 9807 : new_params.safe_push (vtype);
840 : :
841 : 7823 : if (node->definition)
842 : 4439 : sc->args[i].simd_array
843 : 8866 : = create_tmp_simd_array (DECL_NAME (parm)
844 : 4427 : ? IDENTIFIER_POINTER (DECL_NAME (parm))
845 : : : NULL, parm_type, sc->simdlen);
846 : : }
847 : : }
848 : :
849 : 7176 : if (sc->inbranch)
850 : : {
851 : 2191 : tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
852 : 2191 : tree mask_type;
853 : 2191 : if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
854 : 1589 : veclen = sc->vecsize_int;
855 : : else
856 : 602 : veclen = sc->vecsize_float;
857 : 2191 : if (known_eq (veclen, 0U))
858 : 0 : veclen = sc->simdlen;
859 : : else
860 : 4382 : veclen = exact_div (veclen,
861 : 4382 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type)));
862 : 2191 : if (multiple_p (veclen, sc->simdlen))
863 : 2093 : veclen = sc->simdlen;
864 : 2191 : if (sc->mask_mode != VOIDmode)
865 : 537 : mask_type
866 : 537 : = lang_hooks.types.type_for_mode (sc->mask_mode, 1);
867 : 1654 : else if (POINTER_TYPE_P (base_type))
868 : 19 : mask_type = build_vector_type (pointer_sized_int_node, veclen);
869 : : else
870 : 1635 : mask_type = build_vector_type (base_type, veclen);
871 : :
872 : 2191 : k = vector_unroll_factor (sc->simdlen, veclen);
873 : :
874 : : /* We have previously allocated one extra entry for the mask. Use
875 : : it and fill it. */
876 : 2191 : sc->nargs++;
877 : 2191 : if (sc->mask_mode != VOIDmode)
878 : 537 : base_type = boolean_type_node;
879 : 2191 : if (node->definition)
880 : : {
881 : 1947 : sc->args[i].orig_arg
882 : 1947 : = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type);
883 : 1947 : if (sc->mask_mode == VOIDmode)
884 : 1471 : sc->args[i].simd_array
885 : 1471 : = create_tmp_simd_array ("mask", base_type, sc->simdlen);
886 : 476 : else if (k > 1)
887 : 1 : sc->args[i].simd_array
888 : 1 : = create_tmp_simd_array ("mask", mask_type, k);
889 : : else
890 : 475 : sc->args[i].simd_array = NULL_TREE;
891 : : }
892 : 2191 : sc->args[i].orig_type = base_type;
893 : 2191 : sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK;
894 : 2191 : sc->args[i].vector_type = mask_type;
895 : : }
896 : :
897 : 7176 : if (!node->definition)
898 : : {
899 : 2724 : tree new_arg_types = NULL_TREE, new_reversed;
900 : 2724 : bool last_parm_void = false;
901 : 5448 : if (args.length () > 0 && args.last () == void_type_node)
902 : : last_parm_void = true;
903 : :
904 : 2724 : gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
905 : 6793 : for (i = 0; i < new_params.length (); i++)
906 : 4069 : new_arg_types = tree_cons (NULL_TREE, new_params[i], new_arg_types);
907 : 2724 : new_reversed = nreverse (new_arg_types);
908 : 2724 : if (last_parm_void)
909 : : {
910 : 2724 : if (new_reversed)
911 : 2724 : TREE_CHAIN (new_arg_types) = void_list_node;
912 : : else
913 : 0 : new_reversed = void_list_node;
914 : : }
915 : 2724 : TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed;
916 : : }
917 : 7176 : }
918 : :
919 : : /* Initialize and copy the function arguments in NODE to their
920 : : corresponding local simd arrays. Returns a fresh gimple_seq with
921 : : the instruction sequence generated. */
922 : :
923 : : static gimple_seq
924 : 4452 : simd_clone_init_simd_arrays (struct cgraph_node *node,
925 : : ipa_param_body_adjustments *adjustments)
926 : : {
927 : 4452 : gimple_seq seq = NULL;
928 : 4452 : unsigned i = 0, j = 0, k;
929 : :
930 : 4452 : for (tree arg = DECL_ARGUMENTS (node->decl);
931 : 14776 : arg;
932 : 10324 : arg = DECL_CHAIN (arg), i++, j++)
933 : : {
934 : 10324 : ipa_adjusted_param adj = (*adjustments->m_adj_params)[j];
935 : 14262 : if (adj.op == IPA_PARAM_OP_COPY
936 : 10324 : || POINTER_TYPE_P (TREE_TYPE (arg)))
937 : 8352 : continue;
938 : :
939 : 6386 : node->simdclone->args[i].vector_arg = arg;
940 : :
941 : 6386 : tree array = node->simdclone->args[i].simd_array;
942 : 6386 : if (node->simdclone->mask_mode != VOIDmode
943 : 1540 : && adj.param_prefix_index == IPA_PARAM_PREFIX_MASK)
944 : : {
945 : 476 : if (array == NULL_TREE)
946 : 475 : continue;
947 : 1 : unsigned int l
948 : 1 : = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array))));
949 : 5 : for (k = 0; k <= l; k++)
950 : : {
951 : 4 : if (k)
952 : : {
953 : 3 : arg = DECL_CHAIN (arg);
954 : 3 : j++;
955 : : }
956 : 4 : tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
957 : 4 : array, size_int (k), NULL, NULL);
958 : 4 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
959 : 4 : gimplify_and_add (t, &seq);
960 : : }
961 : 1 : continue;
962 : 1 : }
963 : 5910 : if (!VECTOR_TYPE_P (TREE_TYPE (arg))
964 : 5910 : || known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)),
965 : : node->simdclone->simdlen))
966 : : {
967 : 4483 : tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
968 : 4483 : tree ptr = build_fold_addr_expr (array);
969 : 4483 : tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
970 : 4483 : build_int_cst (ptype, 0));
971 : 4483 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
972 : 4483 : gimplify_and_add (t, &seq);
973 : : }
974 : : else
975 : : {
976 : 1427 : poly_uint64 simdlen = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg));
977 : 1427 : unsigned int times = vector_unroll_factor (node->simdclone->simdlen,
978 : : simdlen);
979 : 1427 : tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
980 : 4699 : for (k = 0; k < times; k++)
981 : : {
982 : 3272 : tree ptr = build_fold_addr_expr (array);
983 : 3272 : int elemsize;
984 : 3272 : if (k)
985 : : {
986 : 1845 : arg = DECL_CHAIN (arg);
987 : 1845 : j++;
988 : : }
989 : 3272 : tree elemtype = TREE_TYPE (TREE_TYPE (arg));
990 : 3272 : elemsize = GET_MODE_SIZE (SCALAR_TYPE_MODE (elemtype));
991 : 3272 : tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
992 : 3272 : build_int_cst (ptype, k * elemsize * simdlen));
993 : 3272 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
994 : 3272 : gimplify_and_add (t, &seq);
995 : : }
996 : : }
997 : : }
998 : 4452 : return seq;
999 : : }
1000 : :
1001 : : /* Callback info for ipa_simd_modify_stmt_ops below. */
1002 : :
1003 : : struct modify_stmt_info {
1004 : : ipa_param_body_adjustments *adjustments;
1005 : : gimple *stmt;
1006 : : gimple *after_stmt;
1007 : : /* True if the parent statement was modified by
1008 : : ipa_simd_modify_stmt_ops. */
1009 : : bool modified;
1010 : : };
1011 : :
1012 : : /* Callback for walk_gimple_op.
1013 : :
1014 : : Adjust operands from a given statement as specified in the
1015 : : adjustments vector in the callback data. */
1016 : :
1017 : : static tree
1018 : 124629 : ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
1019 : : {
1020 : 124629 : struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1021 : 124629 : struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
1022 : 124629 : tree *orig_tp = tp;
1023 : 124629 : if (TREE_CODE (*tp) == ADDR_EXPR)
1024 : 8116 : tp = &TREE_OPERAND (*tp, 0);
1025 : :
1026 : 124629 : if (TREE_CODE (*tp) == BIT_FIELD_REF
1027 : 124629 : || TREE_CODE (*tp) == IMAGPART_EXPR
1028 : 124629 : || TREE_CODE (*tp) == REALPART_EXPR)
1029 : 0 : tp = &TREE_OPERAND (*tp, 0);
1030 : :
1031 : 124629 : tree repl = NULL_TREE;
1032 : 124629 : ipa_param_body_replacement *pbr = NULL;
1033 : :
1034 : 124629 : if (TREE_CODE (*tp) == PARM_DECL)
1035 : : {
1036 : 2084 : pbr = info->adjustments->get_expr_replacement (*tp, true);
1037 : 2084 : if (pbr)
1038 : 1304 : repl = pbr->repl;
1039 : : }
1040 : 122545 : else if (TYPE_P (*tp))
1041 : 0 : *walk_subtrees = 0;
1042 : :
1043 : 1304 : if (repl)
1044 : 1304 : repl = unshare_expr (repl);
1045 : : else
1046 : : {
1047 : 123325 : if (tp != orig_tp)
1048 : : {
1049 : 7384 : *walk_subtrees = 0;
1050 : 7384 : bool modified = info->modified;
1051 : 7384 : info->modified = false;
1052 : 7384 : walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset);
1053 : 7384 : if (!info->modified)
1054 : : {
1055 : 7200 : info->modified = modified;
1056 : 7200 : return NULL_TREE;
1057 : : }
1058 : 184 : info->modified = modified;
1059 : 184 : repl = *tp;
1060 : : }
1061 : : else
1062 : : return NULL_TREE;
1063 : : }
1064 : :
1065 : 1488 : if (tp != orig_tp)
1066 : : {
1067 : 916 : if (gimple_code (info->stmt) == GIMPLE_PHI
1068 : 48 : && pbr
1069 : 40 : && TREE_CODE (*orig_tp) == ADDR_EXPR
1070 : 40 : && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL
1071 : 956 : && pbr->dummy)
1072 : : {
1073 : 0 : gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME);
1074 : 0 : *orig_tp = pbr->dummy;
1075 : 0 : info->modified = true;
1076 : 0 : return NULL_TREE;
1077 : : }
1078 : :
1079 : 916 : repl = build_fold_addr_expr (repl);
1080 : 916 : gimple *stmt;
1081 : 916 : if (is_gimple_debug (info->stmt))
1082 : : {
1083 : 88 : tree vexpr = build_debug_expr_decl (TREE_TYPE (repl));
1084 : 88 : stmt = gimple_build_debug_source_bind (vexpr, repl, NULL);
1085 : 88 : repl = vexpr;
1086 : : }
1087 : : else
1088 : : {
1089 : 828 : stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
1090 : 828 : repl = gimple_assign_lhs (stmt);
1091 : : }
1092 : 916 : gimple_stmt_iterator gsi;
1093 : 916 : if (gimple_code (info->stmt) == GIMPLE_PHI)
1094 : : {
1095 : 48 : if (info->after_stmt)
1096 : 8 : gsi = gsi_for_stmt (info->after_stmt);
1097 : : else
1098 : 40 : gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
1099 : : /* Cache SSA_NAME for next time. */
1100 : 48 : if (pbr
1101 : 40 : && TREE_CODE (*orig_tp) == ADDR_EXPR
1102 : 88 : && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL)
1103 : : {
1104 : 40 : gcc_assert (!pbr->dummy);
1105 : 40 : pbr->dummy = repl;
1106 : : }
1107 : : }
1108 : : else
1109 : 868 : gsi = gsi_for_stmt (info->stmt);
1110 : 916 : if (info->after_stmt)
1111 : 8 : gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
1112 : : else
1113 : 908 : gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1114 : 916 : if (gimple_code (info->stmt) == GIMPLE_PHI)
1115 : 48 : info->after_stmt = stmt;
1116 : 916 : *orig_tp = repl;
1117 : : }
1118 : 572 : else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
1119 : : {
1120 : 0 : tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
1121 : 0 : *tp = vce;
1122 : : }
1123 : : else
1124 : 572 : *tp = repl;
1125 : :
1126 : 1488 : info->modified = true;
1127 : 1488 : return NULL_TREE;
1128 : : }
1129 : :
1130 : : /* Traverse the function body and perform all modifications as
1131 : : described in ADJUSTMENTS. At function return, ADJUSTMENTS will be
1132 : : modified such that the replacement/reduction value will now be an
1133 : : offset into the corresponding simd_array.
1134 : :
1135 : : This function will replace all function argument uses with their
1136 : : corresponding simd array elements, and ajust the return values
1137 : : accordingly. */
1138 : :
1139 : : static void
1140 : 4452 : ipa_simd_modify_function_body (struct cgraph_node *node,
1141 : : ipa_param_body_adjustments *adjustments,
1142 : : tree retval_array, tree iter)
1143 : : {
1144 : 4452 : basic_block bb;
1145 : 4452 : unsigned int i, j;
1146 : :
1147 : :
1148 : : /* Register replacements for every function argument use to an offset into
1149 : : the corresponding simd_array. */
1150 : 14776 : for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
1151 : : {
1152 : 16209 : if (!node->simdclone->args[i].vector_arg
1153 : 10324 : || (*adjustments->m_adj_params)[j].user_flag)
1154 : 5885 : continue;
1155 : :
1156 : 4439 : tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1157 : 4439 : tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
1158 : 4439 : tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
1159 : : iter, NULL_TREE, NULL_TREE);
1160 : 4439 : adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
1161 : :
1162 : 4439 : if (multiple_p (node->simdclone->simdlen, TYPE_VECTOR_SUBPARTS (vectype)))
1163 : 4439 : j += vector_unroll_factor (node->simdclone->simdlen,
1164 : 4439 : TYPE_VECTOR_SUBPARTS (vectype)) - 1;
1165 : : }
1166 : 4452 : adjustments->sort_replacements ();
1167 : :
1168 : 4452 : tree name;
1169 : 45451 : FOR_EACH_SSA_NAME (i, name, cfun)
1170 : : {
1171 : 40999 : tree base_var;
1172 : 40999 : if (SSA_NAME_VAR (name)
1173 : 23921 : && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
1174 : 7945 : && (base_var
1175 : 7945 : = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
1176 : : {
1177 : 4451 : if (SSA_NAME_IS_DEFAULT_DEF (name))
1178 : : {
1179 : 4019 : tree old_decl = SSA_NAME_VAR (name);
1180 : 4019 : bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1181 : 4019 : gimple_stmt_iterator gsi = gsi_after_labels (bb);
1182 : 4019 : tree repl = adjustments->lookup_replacement (old_decl, 0);
1183 : 4019 : gcc_checking_assert (repl);
1184 : 4019 : repl = unshare_expr (repl);
1185 : 4019 : set_ssa_default_def (cfun, old_decl, NULL_TREE);
1186 : 4019 : SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1187 : 4019 : SSA_NAME_IS_DEFAULT_DEF (name) = 0;
1188 : 4019 : gimple *stmt = gimple_build_assign (name, repl);
1189 : 4019 : gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1190 : : }
1191 : : else
1192 : 864 : SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1193 : : }
1194 : : }
1195 : :
1196 : 4452 : struct modify_stmt_info info;
1197 : 4452 : info.adjustments = adjustments;
1198 : :
1199 : 19514 : FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
1200 : : {
1201 : 15062 : gimple_stmt_iterator gsi;
1202 : :
1203 : 17686 : for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1204 : : {
1205 : 2624 : gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
1206 : 2624 : int i, n = gimple_phi_num_args (phi);
1207 : 2624 : info.stmt = phi;
1208 : 2624 : info.after_stmt = NULL;
1209 : 2624 : struct walk_stmt_info wi;
1210 : 2624 : memset (&wi, 0, sizeof (wi));
1211 : 2624 : info.modified = false;
1212 : 2624 : wi.info = &info;
1213 : 8780 : for (i = 0; i < n; ++i)
1214 : : {
1215 : 6156 : int walk_subtrees = 1;
1216 : 6156 : tree arg = gimple_phi_arg_def (phi, i);
1217 : 6156 : tree op = arg;
1218 : 6156 : ipa_simd_modify_stmt_ops (&op, &walk_subtrees, &wi);
1219 : 6156 : if (op != arg)
1220 : : {
1221 : 40 : SET_PHI_ARG_DEF (phi, i, op);
1222 : 40 : gcc_assert (TREE_CODE (op) == SSA_NAME);
1223 : 40 : if (gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL)
1224 : 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
1225 : : }
1226 : : }
1227 : : }
1228 : :
1229 : 15062 : gsi = gsi_start_bb (bb);
1230 : 61915 : while (!gsi_end_p (gsi))
1231 : : {
1232 : 46853 : gimple *stmt = gsi_stmt (gsi);
1233 : 46853 : info.stmt = stmt;
1234 : 46853 : info.after_stmt = NULL;
1235 : 46853 : struct walk_stmt_info wi;
1236 : :
1237 : 46853 : memset (&wi, 0, sizeof (wi));
1238 : 46853 : info.modified = false;
1239 : 46853 : wi.info = &info;
1240 : 46853 : walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
1241 : :
1242 : 46853 : if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
1243 : : {
1244 : 4372 : tree retval = gimple_return_retval (return_stmt);
1245 : 4372 : edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
1246 : 4372 : e->flags |= EDGE_FALLTHRU;
1247 : 4372 : if (!retval)
1248 : : {
1249 : 720 : gsi_remove (&gsi, true);
1250 : 744 : continue;
1251 : : }
1252 : :
1253 : : /* Replace `return foo' with `retval_array[iter] = foo'. */
1254 : 3652 : tree ref = build4 (ARRAY_REF, TREE_TYPE (retval),
1255 : : retval_array, iter, NULL, NULL);
1256 : 3652 : stmt = gimple_build_assign (ref, retval);
1257 : 3652 : gsi_replace (&gsi, stmt, true);
1258 : 3652 : info.modified = true;
1259 : : }
1260 : :
1261 : 46133 : if (info.modified)
1262 : : {
1263 : 4772 : update_stmt (stmt);
1264 : : /* If the above changed the var of a debug bind into something
1265 : : different, remove the debug stmt. We could also for all the
1266 : : replaced parameters add VAR_DECLs for debug info purposes,
1267 : : add debug stmts for those to be the simd array accesses and
1268 : : replace debug stmt var operand with that var. Debugging of
1269 : : vectorized loops doesn't work too well, so don't bother for
1270 : : now. */
1271 : 4828 : if ((gimple_debug_bind_p (stmt)
1272 : 80 : && !DECL_P (gimple_debug_bind_get_var (stmt)))
1273 : 136 : || (gimple_debug_source_bind_p (stmt)
1274 : 0 : && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
1275 : : {
1276 : 24 : gsi_remove (&gsi, true);
1277 : 24 : continue;
1278 : : }
1279 : 4748 : if (maybe_clean_eh_stmt (stmt))
1280 : 0 : gimple_purge_dead_eh_edges (gimple_bb (stmt));
1281 : : }
1282 : 46109 : gsi_next (&gsi);
1283 : : }
1284 : : }
1285 : 4452 : }
1286 : :
1287 : : /* Helper function of simd_clone_adjust, return linear step addend
1288 : : of Ith argument. */
1289 : :
1290 : : static tree
1291 : 2091 : simd_clone_linear_addend (struct cgraph_node *node, unsigned int i,
1292 : : tree addtype, basic_block entry_bb)
1293 : : {
1294 : 2091 : tree ptype = NULL_TREE;
1295 : 2091 : switch (node->simdclone->args[i].arg_type)
1296 : : {
1297 : 1939 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
1298 : 1939 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
1299 : 1939 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1300 : 1939 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
1301 : 1939 : return build_int_cst (addtype, node->simdclone->args[i].linear_step);
1302 : 140 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
1303 : 140 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
1304 : 140 : ptype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1305 : 140 : break;
1306 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1307 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1308 : 12 : ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg));
1309 : 12 : break;
1310 : 0 : default:
1311 : 0 : gcc_unreachable ();
1312 : : }
1313 : :
1314 : 152 : unsigned int idx = node->simdclone->args[i].linear_step;
1315 : 152 : tree arg = node->simdclone->args[idx].orig_arg;
1316 : 152 : gcc_assert (is_gimple_reg_type (TREE_TYPE (arg)));
1317 : 152 : gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1318 : 152 : gimple *g;
1319 : 152 : tree ret;
1320 : 152 : if (is_gimple_reg (arg))
1321 : 152 : ret = get_or_create_ssa_default_def (cfun, arg);
1322 : : else
1323 : : {
1324 : 0 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
1325 : 0 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1326 : 0 : ret = gimple_assign_lhs (g);
1327 : : }
1328 : 152 : if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
1329 : : {
1330 : 28 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))),
1331 : : build_simple_mem_ref (ret));
1332 : 28 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1333 : 28 : ret = gimple_assign_lhs (g);
1334 : : }
1335 : 152 : if (!useless_type_conversion_p (addtype, TREE_TYPE (ret)))
1336 : : {
1337 : 60 : g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret);
1338 : 60 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1339 : 60 : ret = gimple_assign_lhs (g);
1340 : : }
1341 : 152 : if (POINTER_TYPE_P (ptype))
1342 : : {
1343 : 60 : tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype));
1344 : 60 : if (size && TREE_CODE (size) == INTEGER_CST)
1345 : : {
1346 : 60 : g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR,
1347 : : ret, fold_convert (addtype, size));
1348 : 60 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1349 : 60 : ret = gimple_assign_lhs (g);
1350 : : }
1351 : : }
1352 : : return ret;
1353 : : }
1354 : :
1355 : : /* Adjust the argument types in NODE to their appropriate vector
1356 : : counterparts. */
1357 : :
1358 : : static void
1359 : 4452 : simd_clone_adjust (struct cgraph_node *node)
1360 : : {
1361 : 4452 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
1362 : :
1363 : 4452 : tree orig_rettype = TREE_TYPE (TREE_TYPE (node->decl));
1364 : 4452 : TREE_TYPE (node->decl) = build_distinct_type_copy (TREE_TYPE (node->decl));
1365 : 4452 : simd_clone_adjust_return_type (node);
1366 : 4452 : simd_clone_adjust_argument_types (node);
1367 : 4452 : targetm.simd_clone.adjust (node);
1368 : 4452 : tree retval = NULL_TREE;
1369 : 4452 : if (orig_rettype != void_type_node)
1370 : : {
1371 : 3708 : poly_uint64 veclen;
1372 : 3708 : if (INTEGRAL_TYPE_P (orig_rettype) || POINTER_TYPE_P (orig_rettype))
1373 : 2803 : veclen = node->simdclone->vecsize_int;
1374 : : else
1375 : 905 : veclen = node->simdclone->vecsize_float;
1376 : 3708 : if (known_eq (veclen, 0U))
1377 : 0 : veclen = node->simdclone->simdlen;
1378 : : else
1379 : 7416 : veclen = exact_div (veclen,
1380 : 7416 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (orig_rettype)));
1381 : 3708 : if (multiple_p (veclen, node->simdclone->simdlen))
1382 : 3507 : veclen = node->simdclone->simdlen;
1383 : :
1384 : 3708 : retval = DECL_RESULT (node->decl);
1385 : : /* Adjust the DECL_RESULT. */
1386 : 3708 : TREE_TYPE (retval) = TREE_TYPE (TREE_TYPE (node->decl));
1387 : 3708 : relayout_decl (retval);
1388 : :
1389 : 7416 : tree atype = build_array_type_nelts (orig_rettype,
1390 : 3708 : node->simdclone->simdlen);
1391 : 3708 : if (maybe_ne (veclen, node->simdclone->simdlen))
1392 : 201 : retval = build1 (VIEW_CONVERT_EXPR, atype, retval);
1393 : : else
1394 : : {
1395 : : /* Set up a SIMD array to use as the return value. */
1396 : 3507 : retval = create_tmp_var_raw (atype, "retval");
1397 : 3507 : gimple_add_tmp_var (retval);
1398 : : }
1399 : : }
1400 : :
1401 : 4452 : struct cgraph_simd_clone *sc = node->simdclone;
1402 : 4452 : vec<ipa_adjusted_param, va_gc> *new_params = NULL;
1403 : 4452 : vec_safe_reserve (new_params, sc->nargs);
1404 : 4452 : unsigned i, j, k;
1405 : 14776 : for (i = 0; i < sc->nargs; ++i)
1406 : : {
1407 : 10324 : ipa_adjusted_param adj;
1408 : 10324 : memset (&adj, 0, sizeof (adj));
1409 : 10324 : poly_uint64 veclen;
1410 : 10324 : tree elem_type;
1411 : :
1412 : 10324 : adj.base_index = i;
1413 : 10324 : adj.prev_clone_index = i;
1414 : 10324 : switch (sc->args[i].arg_type)
1415 : : {
1416 : 3926 : default:
1417 : : /* No adjustment necessary for scalar arguments. */
1418 : 3926 : adj.op = IPA_PARAM_OP_COPY;
1419 : 3926 : break;
1420 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1421 : 12 : adj.op = IPA_PARAM_OP_COPY;
1422 : 12 : break;
1423 : 6386 : case SIMD_CLONE_ARG_TYPE_MASK:
1424 : 6386 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1425 : 6386 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1426 : 6386 : case SIMD_CLONE_ARG_TYPE_VECTOR:
1427 : 6386 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK
1428 : 1947 : && sc->mask_mode != VOIDmode)
1429 : 476 : elem_type = simd_clone_compute_base_data_type (sc->origin, sc);
1430 : : else
1431 : 5910 : elem_type = TREE_TYPE (sc->args[i].vector_type);
1432 : 6386 : if (INTEGRAL_TYPE_P (elem_type) || POINTER_TYPE_P (elem_type))
1433 : 4730 : veclen = sc->vecsize_int;
1434 : : else
1435 : 1656 : veclen = sc->vecsize_float;
1436 : 6386 : if (known_eq (veclen, 0U))
1437 : 0 : veclen = sc->simdlen;
1438 : : else
1439 : 6386 : veclen
1440 : 6386 : = exact_div (veclen,
1441 : 12772 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (elem_type)));
1442 : 6386 : if (multiple_p (veclen, sc->simdlen))
1443 : 4958 : veclen = sc->simdlen;
1444 : 6386 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
1445 : : {
1446 : 1947 : adj.user_flag = 1;
1447 : 1947 : adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
1448 : : }
1449 : : else
1450 : 4439 : adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
1451 : 6386 : adj.op = IPA_PARAM_OP_NEW;
1452 : 6386 : adj.type = sc->args[i].vector_type;
1453 : 6386 : k = vector_unroll_factor (sc->simdlen, veclen);
1454 : 8234 : for (j = 1; j < k; j++)
1455 : : {
1456 : 1848 : vec_safe_push (new_params, adj);
1457 : 1848 : if (j == 1)
1458 : : {
1459 : 1428 : memset (&adj, 0, sizeof (adj));
1460 : 1428 : adj.op = IPA_PARAM_OP_NEW;
1461 : 1428 : adj.user_flag = 1;
1462 : 1428 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
1463 : 89 : adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
1464 : : else
1465 : 1339 : adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
1466 : 1428 : adj.base_index = i;
1467 : 1428 : adj.prev_clone_index = i;
1468 : 1428 : adj.type = sc->args[i].vector_type;
1469 : : }
1470 : : }
1471 : : }
1472 : 10324 : vec_safe_push (new_params, adj);
1473 : : }
1474 : 4452 : ipa_param_body_adjustments *adjustments
1475 : 4452 : = new ipa_param_body_adjustments (new_params, node->decl);
1476 : 4452 : adjustments->modify_formal_parameters ();
1477 : :
1478 : 4452 : push_gimplify_context ();
1479 : :
1480 : 4452 : gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments);
1481 : :
1482 : : /* Adjust all uses of vector arguments accordingly. Adjust all
1483 : : return values accordingly. */
1484 : 4452 : tree iter = create_tmp_var (unsigned_type_node, "iter");
1485 : 4452 : tree iter1 = make_ssa_name (iter);
1486 : 4452 : tree iter2 = NULL_TREE;
1487 : 4452 : ipa_simd_modify_function_body (node, adjustments, retval, iter1);
1488 : 4452 : delete adjustments;
1489 : :
1490 : : /* Initialize the iteration variable. */
1491 : 4452 : basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1492 : 4452 : basic_block body_bb = split_block_after_labels (entry_bb)->dest;
1493 : 4452 : gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1494 : : /* Insert the SIMD array and iv initialization at function
1495 : : entry. */
1496 : 4452 : gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
1497 : :
1498 : 4452 : pop_gimplify_context (NULL);
1499 : :
1500 : 4452 : gimple *g;
1501 : 4452 : basic_block incr_bb = NULL;
1502 : 4452 : class loop *loop = NULL;
1503 : :
1504 : : /* Create a new BB right before the original exit BB, to hold the
1505 : : iteration increment and the condition/branch. */
1506 : 4452 : if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1507 : : {
1508 : 4332 : basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
1509 : 4332 : incr_bb = create_empty_bb (orig_exit);
1510 : 4332 : incr_bb->count = profile_count::zero ();
1511 : 4332 : add_bb_to_loop (incr_bb, body_bb->loop_father);
1512 : 13036 : while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1513 : : {
1514 : 4372 : edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1515 : 4372 : redirect_edge_succ (e, incr_bb);
1516 : 4372 : incr_bb->count += e->count ();
1517 : : }
1518 : : }
1519 : 120 : else if (node->simdclone->inbranch)
1520 : : {
1521 : 60 : incr_bb = create_empty_bb (entry_bb);
1522 : 60 : incr_bb->count = profile_count::zero ();
1523 : 60 : add_bb_to_loop (incr_bb, body_bb->loop_father);
1524 : : }
1525 : :
1526 : 60 : if (incr_bb)
1527 : : {
1528 : 4392 : make_single_succ_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1529 : 4392 : gsi = gsi_last_bb (incr_bb);
1530 : 4392 : iter2 = make_ssa_name (iter);
1531 : 4392 : g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
1532 : 4392 : build_int_cst (unsigned_type_node, 1));
1533 : 4392 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1534 : :
1535 : : /* Mostly annotate the loop for the vectorizer (the rest is done
1536 : : below). */
1537 : 4392 : loop = alloc_loop ();
1538 : 4392 : cfun->has_force_vectorize_loops = true;
1539 : : /* We can assert that safelen is the 'minimum' simdlen. */
1540 : 4392 : loop->safelen = constant_lower_bound (node->simdclone->simdlen);
1541 : 4392 : loop->force_vectorize = true;
1542 : 4392 : loop->header = body_bb;
1543 : : }
1544 : :
1545 : : /* Branch around the body if the mask applies. */
1546 : 4452 : if (node->simdclone->inbranch)
1547 : : {
1548 : 1947 : gsi = gsi_last_bb (loop->header);
1549 : 1947 : tree mask_array
1550 : 1947 : = node->simdclone->args[node->simdclone->nargs - 1].simd_array;
1551 : 1947 : tree mask;
1552 : 1947 : if (node->simdclone->mask_mode != VOIDmode)
1553 : : {
1554 : 476 : tree shift_cnt;
1555 : 476 : if (mask_array == NULL_TREE)
1556 : : {
1557 : 475 : tree arg = node->simdclone->args[node->simdclone->nargs
1558 : : - 1].vector_arg;
1559 : 475 : mask = get_or_create_ssa_default_def (cfun, arg);
1560 : 475 : shift_cnt = iter1;
1561 : : }
1562 : : else
1563 : : {
1564 : 1 : tree maskt = TREE_TYPE (mask_array);
1565 : 1 : int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt)));
1566 : : /* For now, c must be constant here. */
1567 : 1 : c = exact_div (node->simdclone->simdlen, c + 1).to_constant ();
1568 : 1 : int s = exact_log2 (c);
1569 : 1 : gcc_assert (s > 0);
1570 : 1 : c--;
1571 : 1 : tree idx = make_ssa_name (TREE_TYPE (iter1));
1572 : 1 : g = gimple_build_assign (idx, RSHIFT_EXPR, iter1,
1573 : 1 : build_int_cst (NULL_TREE, s));
1574 : 1 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1575 : 1 : mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1576 : 1 : tree aref = build4 (ARRAY_REF,
1577 : 1 : TREE_TYPE (TREE_TYPE (mask_array)),
1578 : : mask_array, idx, NULL, NULL);
1579 : 1 : g = gimple_build_assign (mask, aref);
1580 : 1 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1581 : 1 : shift_cnt = make_ssa_name (TREE_TYPE (iter1));
1582 : 1 : g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1,
1583 : 1 : build_int_cst (TREE_TYPE (iter1), c));
1584 : 1 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1585 : : }
1586 : 476 : tree shift_cnt_conv = shift_cnt;
1587 : 476 : if (!useless_type_conversion_p (TREE_TYPE (mask),
1588 : 476 : TREE_TYPE (shift_cnt)))
1589 : : {
1590 : 7 : shift_cnt_conv = make_ssa_name (TREE_TYPE (mask));
1591 : 7 : g = gimple_build_assign (shift_cnt_conv, NOP_EXPR, shift_cnt);
1592 : 7 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1593 : : }
1594 : 476 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1595 : : RSHIFT_EXPR, mask, shift_cnt_conv);
1596 : 476 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1597 : 476 : mask = gimple_assign_lhs (g);
1598 : 476 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1599 : : BIT_AND_EXPR, mask,
1600 : 476 : build_one_cst (TREE_TYPE (mask)));
1601 : 476 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1602 : 476 : mask = gimple_assign_lhs (g);
1603 : : }
1604 : : else
1605 : : {
1606 : 1471 : mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1607 : 1471 : tree aref = build4 (ARRAY_REF,
1608 : 1471 : TREE_TYPE (TREE_TYPE (mask_array)),
1609 : : mask_array, iter1, NULL, NULL);
1610 : 1471 : g = gimple_build_assign (mask, aref);
1611 : 1471 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1612 : 1471 : int bitsize = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (aref)));
1613 : 1471 : if (!INTEGRAL_TYPE_P (TREE_TYPE (aref)))
1614 : : {
1615 : 352 : aref = build1 (VIEW_CONVERT_EXPR,
1616 : : build_nonstandard_integer_type (bitsize, 0),
1617 : : mask);
1618 : 352 : mask = make_ssa_name (TREE_TYPE (aref));
1619 : 352 : g = gimple_build_assign (mask, aref);
1620 : 352 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1621 : : }
1622 : : }
1623 : :
1624 : 1947 : g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)),
1625 : : NULL, NULL);
1626 : 1947 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1627 : 1947 : edge e = make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE);
1628 : 1947 : e->probability = profile_probability::unlikely ().guessed ();
1629 : 1947 : incr_bb->count += e->count ();
1630 : 1947 : edge fallthru = FALLTHRU_EDGE (loop->header);
1631 : 1947 : fallthru->flags = EDGE_FALSE_VALUE;
1632 : 1947 : fallthru->probability = profile_probability::likely ().guessed ();
1633 : : }
1634 : :
1635 : 4452 : basic_block latch_bb = NULL;
1636 : 4452 : basic_block new_exit_bb = NULL;
1637 : :
1638 : : /* Generate the condition. */
1639 : 4452 : if (incr_bb)
1640 : : {
1641 : 4392 : gsi = gsi_last_bb (incr_bb);
1642 : 4392 : g = gimple_build_cond (LT_EXPR, iter2,
1643 : 4392 : build_int_cst (unsigned_type_node,
1644 : 4392 : node->simdclone->simdlen),
1645 : : NULL, NULL);
1646 : 4392 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1647 : 4392 : edge e = split_block (incr_bb, gsi_stmt (gsi));
1648 : 4392 : latch_bb = e->dest;
1649 : 4392 : new_exit_bb = split_block_after_labels (latch_bb)->dest;
1650 : 4392 : loop->latch = latch_bb;
1651 : :
1652 : 4392 : redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
1653 : :
1654 : 4392 : edge new_e = make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
1655 : :
1656 : : /* FIXME: Do we need to distribute probabilities for the conditional? */
1657 : 4392 : new_e->probability = profile_probability::guessed_never ();
1658 : : /* The successor of incr_bb is already pointing to latch_bb; just
1659 : : change the flags.
1660 : : make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE); */
1661 : 4392 : FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
1662 : : }
1663 : :
1664 : 4452 : gphi *phi = create_phi_node (iter1, body_bb);
1665 : 4452 : edge preheader_edge = find_edge (entry_bb, body_bb);
1666 : 4452 : edge latch_edge = NULL;
1667 : 4452 : add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
1668 : : UNKNOWN_LOCATION);
1669 : 4452 : if (incr_bb)
1670 : : {
1671 : 4392 : latch_edge = single_succ_edge (latch_bb);
1672 : 4392 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1673 : :
1674 : : /* Generate the new return. */
1675 : 4392 : gsi = gsi_last_bb (new_exit_bb);
1676 : 4392 : if (retval
1677 : 3696 : && TREE_CODE (retval) == VIEW_CONVERT_EXPR
1678 : 4593 : && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
1679 : 201 : retval = TREE_OPERAND (retval, 0);
1680 : 4191 : else if (retval)
1681 : : {
1682 : 3495 : retval = build1 (VIEW_CONVERT_EXPR,
1683 : 3495 : TREE_TYPE (TREE_TYPE (node->decl)),
1684 : : retval);
1685 : 3495 : retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
1686 : : false, GSI_CONTINUE_LINKING);
1687 : : }
1688 : 4392 : g = gimple_build_return (retval);
1689 : 4392 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1690 : : }
1691 : :
1692 : : /* Handle aligned clauses by replacing default defs of the aligned
1693 : : uniform args with __builtin_assume_aligned (arg_N(D), alignment)
1694 : : lhs. Handle linear by adding PHIs. */
1695 : 14776 : for (unsigned i = 0; i < node->simdclone->nargs; i++)
1696 : 10324 : if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1697 : 10324 : && (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg)
1698 : 1543 : || !is_gimple_reg_type
1699 : 1543 : (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1700 : : {
1701 : 236 : tree orig_arg = node->simdclone->args[i].orig_arg;
1702 : 236 : if (is_gimple_reg_type (TREE_TYPE (orig_arg)))
1703 : 208 : iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1704 : : else
1705 : : {
1706 : 28 : iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg));
1707 : 28 : gimple_add_tmp_var (iter1);
1708 : : }
1709 : 236 : gsi = gsi_after_labels (entry_bb);
1710 : 236 : g = gimple_build_assign (iter1, orig_arg);
1711 : 236 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1712 : 236 : gsi = gsi_after_labels (body_bb);
1713 : 236 : g = gimple_build_assign (orig_arg, iter1);
1714 : 236 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1715 : : }
1716 : 10088 : else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1717 : 1515 : && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg)
1718 : 276 : && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1719 : : == REFERENCE_TYPE
1720 : 10348 : && TREE_ADDRESSABLE
1721 : : (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1722 : : {
1723 : 52 : tree orig_arg = node->simdclone->args[i].orig_arg;
1724 : 52 : tree def = ssa_default_def (cfun, orig_arg);
1725 : 52 : if (def && !has_zero_uses (def))
1726 : : {
1727 : 52 : iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg)));
1728 : 52 : gimple_add_tmp_var (iter1);
1729 : 52 : gsi = gsi_after_labels (entry_bb);
1730 : 52 : g = gimple_build_assign (iter1, build_simple_mem_ref (def));
1731 : 52 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1732 : 52 : gsi = gsi_after_labels (body_bb);
1733 : 52 : g = gimple_build_assign (build_simple_mem_ref (def), iter1);
1734 : 52 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1735 : : }
1736 : : }
1737 : 10036 : else if (node->simdclone->args[i].alignment
1738 : 364 : && node->simdclone->args[i].arg_type
1739 : : == SIMD_CLONE_ARG_TYPE_UNIFORM
1740 : 192 : && (node->simdclone->args[i].alignment
1741 : 192 : & (node->simdclone->args[i].alignment - 1)) == 0
1742 : 10228 : && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1743 : : == POINTER_TYPE)
1744 : : {
1745 : 192 : unsigned int alignment = node->simdclone->args[i].alignment;
1746 : 192 : tree orig_arg = node->simdclone->args[i].orig_arg;
1747 : 192 : tree def = ssa_default_def (cfun, orig_arg);
1748 : 192 : if (def && !has_zero_uses (def))
1749 : : {
1750 : 184 : tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
1751 : 184 : gimple_seq seq = NULL;
1752 : 184 : bool need_cvt = false;
1753 : 184 : gcall *call
1754 : 184 : = gimple_build_call (fn, 2, def, size_int (alignment));
1755 : 184 : g = call;
1756 : 184 : if (!useless_type_conversion_p (TREE_TYPE (orig_arg),
1757 : : ptr_type_node))
1758 : 0 : need_cvt = true;
1759 : 0 : tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg);
1760 : 184 : gimple_call_set_lhs (g, t);
1761 : 184 : gimple_seq_add_stmt_without_update (&seq, g);
1762 : 184 : if (need_cvt)
1763 : : {
1764 : 0 : t = make_ssa_name (orig_arg);
1765 : 0 : g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g));
1766 : 0 : gimple_seq_add_stmt_without_update (&seq, g);
1767 : : }
1768 : 184 : gsi_insert_seq_on_edge_immediate
1769 : 184 : (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
1770 : :
1771 : 184 : entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1772 : 184 : node->create_edge (cgraph_node::get_create (fn),
1773 : : call, entry_bb->count);
1774 : :
1775 : 184 : imm_use_iterator iter;
1776 : 184 : use_operand_p use_p;
1777 : 184 : gimple *use_stmt;
1778 : 184 : tree repl = gimple_get_lhs (g);
1779 : 552 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1780 : 368 : if (is_gimple_debug (use_stmt) || use_stmt == call)
1781 : 184 : continue;
1782 : : else
1783 : 552 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1784 : 368 : SET_USE (use_p, repl);
1785 : : }
1786 : : }
1787 : 9844 : else if ((node->simdclone->args[i].arg_type
1788 : : == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
1789 : 8301 : || (node->simdclone->args[i].arg_type
1790 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
1791 : 7969 : || (node->simdclone->args[i].arg_type
1792 : : == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP)
1793 : 7857 : || (node->simdclone->args[i].arg_type
1794 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP))
1795 : : {
1796 : 2015 : tree orig_arg = node->simdclone->args[i].orig_arg;
1797 : 2015 : gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1798 : : || POINTER_TYPE_P (TREE_TYPE (orig_arg)));
1799 : 2015 : tree def = NULL_TREE;
1800 : 2015 : if (TREE_ADDRESSABLE (orig_arg))
1801 : : {
1802 : 100 : def = make_ssa_name (TREE_TYPE (orig_arg));
1803 : 100 : iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1804 : 100 : if (incr_bb)
1805 : 88 : iter2 = make_ssa_name (TREE_TYPE (orig_arg));
1806 : 100 : gsi = gsi_after_labels (entry_bb);
1807 : 100 : g = gimple_build_assign (def, orig_arg);
1808 : 100 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1809 : : }
1810 : : else
1811 : : {
1812 : 1915 : def = ssa_default_def (cfun, orig_arg);
1813 : 1915 : if (!def || has_zero_uses (def))
1814 : : def = NULL_TREE;
1815 : : else
1816 : : {
1817 : 1867 : iter1 = make_ssa_name (orig_arg);
1818 : 1867 : if (incr_bb)
1819 : 1843 : iter2 = make_ssa_name (orig_arg);
1820 : : }
1821 : : }
1822 : 1967 : if (def)
1823 : : {
1824 : 1967 : phi = create_phi_node (iter1, body_bb);
1825 : 1967 : add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
1826 : 1967 : if (incr_bb)
1827 : : {
1828 : 1931 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1829 : 3862 : enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1830 : 1931 : ? PLUS_EXPR : POINTER_PLUS_EXPR;
1831 : 3862 : tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1832 : 3862 : ? TREE_TYPE (orig_arg) : sizetype;
1833 : 1931 : tree addcst = simd_clone_linear_addend (node, i, addtype,
1834 : : entry_bb);
1835 : 1931 : gsi = gsi_last_bb (incr_bb);
1836 : 1931 : g = gimple_build_assign (iter2, code, iter1, addcst);
1837 : 1931 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1838 : : }
1839 : :
1840 : 1967 : imm_use_iterator iter;
1841 : 1967 : use_operand_p use_p;
1842 : 1967 : gimple *use_stmt;
1843 : 1967 : if (TREE_ADDRESSABLE (orig_arg))
1844 : : {
1845 : 100 : gsi = gsi_after_labels (body_bb);
1846 : 100 : g = gimple_build_assign (orig_arg, iter1);
1847 : 100 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1848 : : }
1849 : : else
1850 : 5861 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1851 : 3994 : if (use_stmt == phi)
1852 : 1867 : continue;
1853 : : else
1854 : 6381 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1855 : 3994 : SET_USE (use_p, iter1);
1856 : : }
1857 : : }
1858 : 7829 : else if (node->simdclone->args[i].arg_type
1859 : : == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP
1860 : 7829 : || (node->simdclone->args[i].arg_type
1861 : : == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP))
1862 : : {
1863 : 172 : tree orig_arg = node->simdclone->args[i].orig_arg;
1864 : 172 : tree def = ssa_default_def (cfun, orig_arg);
1865 : 172 : gcc_assert (!TREE_ADDRESSABLE (orig_arg)
1866 : : && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE);
1867 : 172 : if (def && !has_zero_uses (def))
1868 : : {
1869 : 172 : tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
1870 : 172 : iter1 = make_ssa_name (orig_arg);
1871 : 172 : if (incr_bb)
1872 : 160 : iter2 = make_ssa_name (orig_arg);
1873 : 172 : tree iter3 = make_ssa_name (rtype);
1874 : 172 : tree iter4 = make_ssa_name (rtype);
1875 : 172 : tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
1876 : 172 : gsi = gsi_after_labels (entry_bb);
1877 : 172 : gimple *load
1878 : 172 : = gimple_build_assign (iter3, build_simple_mem_ref (def));
1879 : 172 : gsi_insert_before (&gsi, load, GSI_NEW_STMT);
1880 : :
1881 : 172 : tree array = node->simdclone->args[i].simd_array;
1882 : 172 : TREE_ADDRESSABLE (array) = 1;
1883 : 172 : tree ptr = build_fold_addr_expr (array);
1884 : 172 : phi = create_phi_node (iter1, body_bb);
1885 : 172 : add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
1886 : 172 : if (incr_bb)
1887 : : {
1888 : 160 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1889 : 160 : g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
1890 : 160 : TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
1891 : 160 : gsi = gsi_last_bb (incr_bb);
1892 : 160 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1893 : : }
1894 : :
1895 : 172 : phi = create_phi_node (iter4, body_bb);
1896 : 172 : add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
1897 : 172 : if (incr_bb)
1898 : : {
1899 : 160 : add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
1900 : 320 : enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1901 : 160 : ? PLUS_EXPR : POINTER_PLUS_EXPR;
1902 : 320 : tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1903 : 320 : ? TREE_TYPE (iter3) : sizetype;
1904 : 160 : tree addcst = simd_clone_linear_addend (node, i, addtype,
1905 : : entry_bb);
1906 : 160 : g = gimple_build_assign (iter5, code, iter4, addcst);
1907 : 160 : gsi = gsi_last_bb (incr_bb);
1908 : 160 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1909 : : }
1910 : :
1911 : 172 : g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
1912 : 172 : gsi = gsi_after_labels (body_bb);
1913 : 172 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1914 : :
1915 : 172 : imm_use_iterator iter;
1916 : 172 : use_operand_p use_p;
1917 : 172 : gimple *use_stmt;
1918 : 676 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1919 : 504 : if (use_stmt == load)
1920 : 172 : continue;
1921 : : else
1922 : 996 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1923 : 504 : SET_USE (use_p, iter1);
1924 : :
1925 : 172 : if (!TYPE_READONLY (rtype) && incr_bb)
1926 : : {
1927 : 112 : tree v = make_ssa_name (rtype);
1928 : 112 : tree aref = build4 (ARRAY_REF, rtype, array,
1929 : : size_zero_node, NULL_TREE,
1930 : : NULL_TREE);
1931 : 112 : gsi = gsi_after_labels (new_exit_bb);
1932 : 112 : g = gimple_build_assign (v, aref);
1933 : 112 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1934 : 112 : g = gimple_build_assign (build_simple_mem_ref (def), v);
1935 : 112 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1936 : : }
1937 : : }
1938 : : }
1939 : :
1940 : 4452 : calculate_dominance_info (CDI_DOMINATORS);
1941 : 4452 : if (loop)
1942 : 4392 : add_loop (loop, loop->header->loop_father);
1943 : 4452 : update_ssa (TODO_update_ssa);
1944 : :
1945 : 4452 : pop_cfun ();
1946 : 4452 : }
1947 : :
1948 : : /* If the function in NODE is tagged as an elemental SIMD function,
1949 : : create the appropriate SIMD clones. */
1950 : :
1951 : : void
1952 : 4351650 : expand_simd_clones (struct cgraph_node *node)
1953 : : {
1954 : 4351650 : tree attr;
1955 : 4351650 : bool explicit_p = true;
1956 : :
1957 : 4351650 : if (node->inlined_to
1958 : 4351650 : || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
1959 : 1305052 : return;
1960 : :
1961 : 3046598 : attr = lookup_attribute ("omp declare simd",
1962 : 3046598 : DECL_ATTRIBUTES (node->decl));
1963 : :
1964 : : /* See if we can add an "omp declare simd" directive implicitly
1965 : : before giving up. */
1966 : : /* FIXME: OpenACC "#pragma acc routine" translates into
1967 : : "omp declare target", but appears also to have some other effects
1968 : : that conflict with generating SIMD clones, causing ICEs. So don't
1969 : : do this if we've got OpenACC instead of OpenMP. */
1970 : 3046598 : if (attr == NULL_TREE
1971 : : #ifdef ACCEL_COMPILER
1972 : : && (flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_ANY
1973 : : || flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_NOHOST)
1974 : : #else
1975 : 3045332 : && (flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_ANY
1976 : 3045261 : || flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_HOST)
1977 : : #endif
1978 : 71 : && !oacc_get_fn_attrib (node->decl)
1979 : 3046669 : && ok_for_auto_simd_clone (node))
1980 : : {
1981 : 4 : attr = tree_cons (get_identifier ("omp declare simd"), NULL,
1982 : 4 : DECL_ATTRIBUTES (node->decl));
1983 : 4 : DECL_ATTRIBUTES (node->decl) = attr;
1984 : 4 : explicit_p = false;
1985 : : }
1986 : :
1987 : 3046598 : if (attr == NULL_TREE)
1988 : : return;
1989 : :
1990 : : /* Ignore
1991 : : #pragma omp declare simd
1992 : : extern int foo ();
1993 : : in C, there we don't know the argument types at all. */
1994 : 1270 : if (!node->definition
1995 : 1270 : && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE)
1996 : : return;
1997 : :
1998 : : /* Call this before creating clone_info, as it might ggc_collect. */
1999 : 1270 : if (node->definition && node->has_gimple_body_p ())
2000 : 660 : node->get_body ();
2001 : :
2002 : 1475 : do
2003 : : {
2004 : : /* Start with parsing the "omp declare simd" attribute(s). */
2005 : 1475 : bool inbranch_clause_specified;
2006 : 1475 : struct cgraph_simd_clone *clone_info
2007 : 1475 : = simd_clone_clauses_extract (node, TREE_VALUE (attr),
2008 : : &inbranch_clause_specified);
2009 : 1475 : if (clone_info == NULL)
2010 : 8 : continue;
2011 : :
2012 : 1474 : poly_uint64 orig_simdlen = clone_info->simdlen;
2013 : 1474 : tree base_type = simd_clone_compute_base_data_type (node, clone_info);
2014 : :
2015 : : /* The target can return 0 (no simd clones should be created),
2016 : : 1 (just one ISA of simd clones should be created) or higher
2017 : : count of ISA variants. In that case, clone_info is initialized
2018 : : for the first ISA variant. */
2019 : 1474 : int count
2020 : 1474 : = targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info,
2021 : : base_type, 0,
2022 : : explicit_p);
2023 : 1474 : if (count == 0)
2024 : 7 : continue;
2025 : :
2026 : : /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED,
2027 : : also create one inbranch and one !inbranch clone of it. */
2028 : 12771 : for (int i = 0; i < count * 2; i++)
2029 : : {
2030 : 11304 : struct cgraph_simd_clone *clone = clone_info;
2031 : 11304 : if (inbranch_clause_specified && (i & 1) != 0)
2032 : 3734 : continue;
2033 : :
2034 : 7570 : if (i != 0)
2035 : : {
2036 : 12206 : clone = simd_clone_struct_alloc (clone_info->nargs
2037 : 6103 : + ((i & 1) != 0));
2038 : 6103 : simd_clone_struct_copy (clone, clone_info);
2039 : : /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen
2040 : : and simd_clone_adjust_argument_types did to the first
2041 : : clone's info. */
2042 : 6103 : clone->nargs -= clone_info->inbranch;
2043 : 6103 : clone->simdlen = orig_simdlen;
2044 : : /* And call the target hook again to get the right ISA. */
2045 : 6103 : targetm.simd_clone.compute_vecsize_and_simdlen (node, clone,
2046 : : base_type,
2047 : : i / 2,
2048 : : explicit_p);
2049 : 6103 : if ((i & 1) != 0)
2050 : 1918 : clone->inbranch = 1;
2051 : : }
2052 : :
2053 : : /* simd_clone_mangle might fail if such a clone has been created
2054 : : already. */
2055 : 7570 : tree id = simd_clone_mangle (node, clone);
2056 : 7570 : if (id == NULL_TREE)
2057 : : {
2058 : 394 : if (i == 0)
2059 : 74 : clone->nargs += clone->inbranch;
2060 : 394 : continue;
2061 : : }
2062 : :
2063 : : /* Only when we are sure we want to create the clone actually
2064 : : clone the function (or definitions) or create another
2065 : : extern FUNCTION_DECL (for prototypes without definitions). */
2066 : 7176 : struct cgraph_node *n = simd_clone_create (node, !explicit_p);
2067 : 7176 : if (n == NULL)
2068 : : {
2069 : 0 : if (i == 0)
2070 : 0 : clone->nargs += clone->inbranch;
2071 : 0 : continue;
2072 : : }
2073 : :
2074 : 7176 : n->simdclone = clone;
2075 : 7176 : clone->origin = node;
2076 : 7176 : clone->next_clone = NULL;
2077 : 7176 : if (node->simd_clones == NULL)
2078 : : {
2079 : 1262 : clone->prev_clone = n;
2080 : 1262 : node->simd_clones = n;
2081 : : }
2082 : : else
2083 : : {
2084 : 5914 : clone->prev_clone = node->simd_clones->simdclone->prev_clone;
2085 : 5914 : clone->prev_clone->simdclone->next_clone = n;
2086 : 5914 : node->simd_clones->simdclone->prev_clone = n;
2087 : : }
2088 : 7176 : symtab->change_decl_assembler_name (n->decl, id);
2089 : : /* And finally adjust the return type, parameters and for
2090 : : definitions also function body. */
2091 : 7176 : if (node->definition)
2092 : 4452 : simd_clone_adjust (n);
2093 : : else
2094 : : {
2095 : 5448 : TREE_TYPE (n->decl)
2096 : 2724 : = build_distinct_type_copy (TREE_TYPE (n->decl));
2097 : 2724 : simd_clone_adjust_return_type (n);
2098 : 2724 : simd_clone_adjust_argument_types (n);
2099 : 2724 : targetm.simd_clone.adjust (n);
2100 : : }
2101 : 7176 : if (dump_file)
2102 : 8 : fprintf (dump_file, "\nGenerated %s clone %s\n",
2103 : 8 : (TREE_PUBLIC (n->decl) ? "global" : "local"),
2104 : 8 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
2105 : : }
2106 : : }
2107 : 1475 : while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
2108 : : }
2109 : :
2110 : : /* Entry point for IPA simd clone creation pass. */
2111 : :
2112 : : static unsigned int
2113 : 227036 : ipa_omp_simd_clone (void)
2114 : : {
2115 : 227036 : struct cgraph_node *node;
2116 : 9157368 : FOR_EACH_FUNCTION (node)
2117 : 4351648 : expand_simd_clones (node);
2118 : 227036 : return 0;
2119 : : }
2120 : :
2121 : : namespace {
2122 : :
2123 : : const pass_data pass_data_omp_simd_clone =
2124 : : {
2125 : : SIMPLE_IPA_PASS, /* type */
2126 : : "simdclone", /* name */
2127 : : OPTGROUP_OMP, /* optinfo_flags */
2128 : : TV_NONE, /* tv_id */
2129 : : ( PROP_ssa | PROP_cfg ), /* properties_required */
2130 : : 0, /* properties_provided */
2131 : : 0, /* properties_destroyed */
2132 : : 0, /* todo_flags_start */
2133 : : 0, /* todo_flags_finish */
2134 : : };
2135 : :
2136 : : class pass_omp_simd_clone : public simple_ipa_opt_pass
2137 : : {
2138 : : public:
2139 : 282866 : pass_omp_simd_clone(gcc::context *ctxt)
2140 : 565732 : : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt)
2141 : : {}
2142 : :
2143 : : /* opt_pass methods: */
2144 : : bool gate (function *) final override;
2145 : 227036 : unsigned int execute (function *) final override
2146 : : {
2147 : 227036 : return ipa_omp_simd_clone ();
2148 : : }
2149 : : };
2150 : :
2151 : : bool
2152 : 227041 : pass_omp_simd_clone::gate (function *)
2153 : : {
2154 : 227041 : return targetm.simd_clone.compute_vecsize_and_simdlen != NULL;
2155 : : }
2156 : :
2157 : : } // anon namespace
2158 : :
2159 : : simple_ipa_opt_pass *
2160 : 282866 : make_pass_omp_simd_clone (gcc::context *ctxt)
2161 : : {
2162 : 282866 : return new pass_omp_simd_clone (ctxt);
2163 : : }
|