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 : 7558 : simd_clone_struct_alloc (int nargs)
263 : : {
264 : 7558 : struct cgraph_simd_clone *clone_info;
265 : 7558 : size_t len = (sizeof (struct cgraph_simd_clone)
266 : 7558 : + nargs * sizeof (struct cgraph_simd_clone_arg));
267 : 7558 : clone_info = (struct cgraph_simd_clone *)
268 : 7558 : ggc_internal_cleared_alloc (len);
269 : 7558 : 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 : 6092 : simd_clone_struct_copy (struct cgraph_simd_clone *to,
276 : : struct cgraph_simd_clone *from)
277 : : {
278 : 6092 : memcpy (to, from, (sizeof (struct cgraph_simd_clone)
279 : 6092 : + ((from->nargs - from->inbranch)
280 : 6092 : * sizeof (struct cgraph_simd_clone_arg))));
281 : 6092 : }
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 : 4701 : simd_clone_vector_of_formal_parm_types (vec<tree> *args, tree fndecl)
289 : : {
290 : 4701 : if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
291 : : {
292 : 4657 : push_function_arg_types (args, TREE_TYPE (fndecl));
293 : 4657 : 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 : 1466 : simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
310 : : bool *inbranch_specified)
311 : : {
312 : 1466 : auto_vec<tree> args;
313 : 1466 : simd_clone_vector_of_formal_parm_types (&args, node->decl);
314 : 1466 : tree t;
315 : 1466 : int n;
316 : 1466 : *inbranch_specified = false;
317 : :
318 : 1466 : n = args.length ();
319 : 2920 : if (n > 0 && args.last () == void_type_node)
320 : 1458 : 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 : 1466 : struct cgraph_simd_clone *clone_info = simd_clone_struct_alloc (n + 1);
325 : 1466 : clone_info->nargs = n;
326 : :
327 : 1466 : if (!clauses)
328 : 172 : goto out;
329 : :
330 : 1294 : clauses = TREE_VALUE (clauses);
331 : 1294 : if (!clauses || TREE_CODE (clauses) != OMP_CLAUSE)
332 : 101 : goto out;
333 : :
334 : 3319 : for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t))
335 : : {
336 : 2126 : switch (OMP_CLAUSE_CODE (t))
337 : : {
338 : 110 : case OMP_CLAUSE_INBRANCH:
339 : 110 : clone_info->inbranch = 1;
340 : 110 : *inbranch_specified = true;
341 : 110 : break;
342 : 833 : case OMP_CLAUSE_NOTINBRANCH:
343 : 833 : clone_info->inbranch = 0;
344 : 833 : *inbranch_specified = true;
345 : 833 : break;
346 : 245 : case OMP_CLAUSE_SIMDLEN:
347 : 245 : clone_info->simdlen
348 : 245 : = TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
349 : 245 : break;
350 : 486 : case OMP_CLAUSE_LINEAR:
351 : 486 : {
352 : 486 : tree decl = OMP_CLAUSE_DECL (t);
353 : 486 : tree step = OMP_CLAUSE_LINEAR_STEP (t);
354 : 486 : int argno = TREE_INT_CST_LOW (decl);
355 : 486 : 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 : 455 : if (POINTER_TYPE_P (args[argno]))
387 : 176 : step = fold_convert (ssizetype, step);
388 : 455 : 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 : 455 : 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 : 455 : enum cgraph_simd_clone_arg_type arg_type;
403 : 455 : 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 : 455 : clone_info->args[argno].arg_type = arg_type;
425 : 455 : clone_info->args[argno].linear_step = tree_to_shwi (step);
426 : : }
427 : : }
428 : : break;
429 : : }
430 : 368 : case OMP_CLAUSE_UNIFORM:
431 : 368 : {
432 : 368 : tree decl = OMP_CLAUSE_DECL (t);
433 : 368 : int argno = tree_to_uhwi (decl);
434 : 368 : clone_info->args[argno].arg_type
435 : 368 : = SIMD_CLONE_ARG_TYPE_UNIFORM;
436 : 368 : 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 : 1193 : out:
456 : 1466 : 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 : 3966 : for (unsigned int argno = 0; argno < clone_info->nargs; argno++)
465 : 2501 : if (TYPE_ATOMIC (args[argno])
466 : 2501 : && 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 : 1466 : }
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 : 4178 : simd_clone_compute_base_data_type (struct cgraph_node *node,
484 : : struct cgraph_simd_clone *clone_info)
485 : : {
486 : 4178 : tree type = integer_type_node;
487 : 4178 : tree fndecl = node->decl;
488 : :
489 : : /* a) For non-void function, the characteristic data type is the
490 : : return type. */
491 : 4178 : if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE)
492 : 3627 : 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 : 4178 : if (RECORD_OR_UNION_TYPE_P (type)
514 : 2 : && !aggregate_value_p (type, NULL)
515 : 4180 : && 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 : 7550 : simd_clone_mangle (struct cgraph_node *node,
531 : : struct cgraph_simd_clone *clone_info)
532 : : {
533 : 7550 : char vecsize_mangle = clone_info->vecsize_mangle;
534 : 7550 : char mask = clone_info->inbranch ? 'M' : 'N';
535 : 7550 : poly_uint64 simdlen = clone_info->simdlen;
536 : 7550 : unsigned int n;
537 : 7550 : pretty_printer pp;
538 : :
539 : 7550 : gcc_assert (vecsize_mangle && maybe_ne (simdlen, 0U));
540 : :
541 : 7550 : pp_string (&pp, "_ZGV");
542 : 7550 : pp_character (&pp, vecsize_mangle);
543 : 7550 : pp_character (&pp, mask);
544 : :
545 : 7550 : unsigned HOST_WIDE_INT len;
546 : 7550 : if (simdlen.is_constant (&len))
547 : 7550 : pp_decimal_int (&pp, (int) (len));
548 : : else
549 : : pp_character (&pp, 'x');
550 : :
551 : 20357 : for (n = 0; n < clone_info->nargs; ++n)
552 : : {
553 : 12807 : struct cgraph_simd_clone_arg arg = clone_info->args[n];
554 : :
555 : 12807 : switch (arg.arg_type)
556 : : {
557 : 2063 : case SIMD_CLONE_ARG_TYPE_UNIFORM:
558 : 2063 : pp_character (&pp, 'u');
559 : 2063 : break;
560 : 1915 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
561 : 1915 : pp_character (&pp, 'l');
562 : 1915 : 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 : 2567 : mangle_linear:
573 : 2567 : gcc_assert (arg.linear_step != 0);
574 : 2567 : if (arg.linear_step > 1)
575 : 1242 : pp_unsigned_wide_integer (&pp, arg.linear_step);
576 : 1325 : 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 : 8013 : default:
600 : 8013 : pp_character (&pp, 'v');
601 : : }
602 : 12807 : if (arg.alignment)
603 : : {
604 : 520 : pp_character (&pp, 'a');
605 : 520 : pp_decimal_int (&pp, arg.alignment);
606 : : }
607 : : }
608 : :
609 : 7550 : pp_underscore (&pp);
610 : 7550 : const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
611 : 7550 : if (*str == '*')
612 : 16 : ++str;
613 : 7550 : pp_string (&pp, str);
614 : 7550 : 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 : 31364 : for (struct cgraph_node *clone = node->simd_clones; clone;
623 : 23814 : clone = clone->simdclone->next_clone)
624 : 24208 : if (id_equal (DECL_ASSEMBLER_NAME (clone->decl), str))
625 : : return NULL_TREE;
626 : :
627 : 7156 : return get_identifier (str);
628 : 7550 : }
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 : 7156 : simd_clone_create (struct cgraph_node *old_node, bool force_local)
636 : : {
637 : 7156 : struct cgraph_node *new_node;
638 : 7156 : if (old_node->definition)
639 : : {
640 : 4472 : if (!old_node->has_gimple_body_p ())
641 : : return NULL;
642 : 4472 : old_node->get_body ();
643 : 4472 : new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL,
644 : : NULL, NULL,
645 : : "simdclone");
646 : : }
647 : : else
648 : : {
649 : 2684 : tree old_decl = old_node->decl;
650 : 2684 : tree new_decl = copy_node (old_node->decl);
651 : 2684 : DECL_NAME (new_decl) = clone_function_name_numbered (old_decl,
652 : : "simdclone");
653 : 2684 : SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
654 : 2684 : SET_DECL_RTL (new_decl, NULL);
655 : 2684 : DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
656 : 2684 : DECL_STATIC_DESTRUCTOR (new_decl) = 0;
657 : 2684 : new_node = old_node->create_version_clone (new_decl, vNULL, NULL);
658 : 2684 : if (old_node->in_other_partition)
659 : 16 : new_node->in_other_partition = 1;
660 : : }
661 : 7156 : if (new_node == NULL)
662 : : return new_node;
663 : :
664 : 7156 : set_decl_built_in_function (new_node->decl, NOT_BUILT_IN, 0);
665 : 7156 : 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 : 7148 : TREE_PUBLIC (new_node->decl) = TREE_PUBLIC (old_node->decl);
678 : 7148 : DECL_COMDAT (new_node->decl) = DECL_COMDAT (old_node->decl);
679 : 7148 : DECL_WEAK (new_node->decl) = DECL_WEAK (old_node->decl);
680 : 7148 : DECL_EXTERNAL (new_node->decl) = DECL_EXTERNAL (old_node->decl);
681 : 14296 : DECL_VISIBILITY_SPECIFIED (new_node->decl)
682 : 7148 : = DECL_VISIBILITY_SPECIFIED (old_node->decl);
683 : 7148 : DECL_VISIBILITY (new_node->decl) = DECL_VISIBILITY (old_node->decl);
684 : 7148 : DECL_DLLIMPORT_P (new_node->decl) = DECL_DLLIMPORT_P (old_node->decl);
685 : 7148 : 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 : 7148 : new_node->local = old_node->local;
693 : 7148 : new_node->externally_visible = old_node->externally_visible;
694 : 7148 : new_node->has_omp_variant_constructs
695 : 7148 : = 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 : 7156 : 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 : 7156 : simd_clone_adjust_return_type (struct cgraph_node *node)
711 : : {
712 : 7156 : tree fndecl = node->decl;
713 : 7156 : tree orig_rettype = TREE_TYPE (TREE_TYPE (fndecl));
714 : 7156 : poly_uint64 veclen;
715 : 7156 : tree t;
716 : :
717 : : /* Adjust the function return type. */
718 : 7156 : if (orig_rettype == void_type_node)
719 : 752 : return;
720 : 6404 : t = TREE_TYPE (TREE_TYPE (fndecl));
721 : 6404 : if (INTEGRAL_TYPE_P (t) || POINTER_TYPE_P (t))
722 : 3091 : veclen = node->simdclone->vecsize_int;
723 : : else
724 : 3313 : veclen = node->simdclone->vecsize_float;
725 : 6404 : if (known_eq (veclen, 0U))
726 : 0 : veclen = node->simdclone->simdlen;
727 : : else
728 : 12808 : veclen = exact_div (veclen, GET_MODE_BITSIZE (SCALAR_TYPE_MODE (t)));
729 : 6404 : if (multiple_p (veclen, node->simdclone->simdlen))
730 : 6162 : veclen = node->simdclone->simdlen;
731 : 6404 : if (POINTER_TYPE_P (t))
732 : 18 : t = pointer_sized_int_node;
733 : 6404 : if (known_eq (veclen, node->simdclone->simdlen))
734 : 6162 : t = build_vector_type (t, node->simdclone->simdlen);
735 : : else
736 : : {
737 : 242 : t = build_vector_type (t, veclen);
738 : 242 : t = build_array_type_nelts (t, exact_div (node->simdclone->simdlen,
739 : : veclen));
740 : : }
741 : 6404 : 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 : 6133 : create_tmp_simd_array (const char *prefix, tree type, poly_uint64 simdlen)
756 : : {
757 : 6133 : tree atype = build_array_type_nelts (type, simdlen);
758 : 6133 : tree avar = create_tmp_var_raw (atype, prefix);
759 : 6133 : gimple_add_tmp_var (avar);
760 : 6133 : 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 : 7156 : simd_clone_adjust_argument_types (struct cgraph_node *node)
777 : : {
778 : 7156 : auto_vec<tree> args;
779 : :
780 : 7156 : if (node->definition)
781 : 4472 : push_function_arg_decls (&args, node->decl);
782 : : else
783 : 2684 : simd_clone_vector_of_formal_parm_types (&args, node->decl);
784 : 7156 : struct cgraph_simd_clone *sc = node->simdclone;
785 : 7156 : unsigned i, k;
786 : 7156 : poly_uint64 veclen;
787 : 7156 : auto_vec<tree> new_params;
788 : :
789 : 19309 : for (i = 0; i < sc->nargs; ++i)
790 : : {
791 : 12153 : tree parm = NULL_TREE;
792 : 12153 : tree parm_type = NULL_TREE;
793 : 12153 : if (i < args.length())
794 : : {
795 : 12153 : parm = args[i];
796 : 12153 : parm_type = node->definition ? TREE_TYPE (parm) : parm;
797 : : }
798 : :
799 : 12153 : sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
800 : 12153 : sc->args[i].orig_type = parm_type;
801 : :
802 : 12153 : switch (sc->args[i].arg_type)
803 : : {
804 : 4138 : default:
805 : 4138 : new_params.safe_push (parm_type);
806 : 8448 : 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 : 7843 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
817 : 7843 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
818 : 7843 : case SIMD_CLONE_ARG_TYPE_VECTOR:
819 : 7843 : if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type))
820 : 3621 : veclen = sc->vecsize_int;
821 : : else
822 : 4222 : veclen = sc->vecsize_float;
823 : 7843 : if (known_eq (veclen, 0U))
824 : 0 : veclen = sc->simdlen;
825 : : else
826 : 7843 : veclen
827 : 7843 : = exact_div (veclen,
828 : 15686 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type)));
829 : 7843 : if (multiple_p (veclen, sc->simdlen))
830 : 6285 : veclen = sc->simdlen;
831 : 7843 : tree vtype;
832 : 7843 : if (POINTER_TYPE_P (parm_type))
833 : 842 : vtype = build_vector_type (pointer_sized_int_node, veclen);
834 : : else
835 : 7001 : vtype = build_vector_type (parm_type, veclen);
836 : 7843 : sc->args[i].vector_type = vtype;
837 : 7843 : k = vector_unroll_factor (sc->simdlen, veclen);
838 : 17746 : for (unsigned j = 0; j < k; j++)
839 : 9903 : new_params.safe_push (vtype);
840 : :
841 : 7843 : if (node->definition)
842 : 4471 : sc->args[i].simd_array
843 : 8930 : = create_tmp_simd_array (DECL_NAME (parm)
844 : 4459 : ? IDENTIFIER_POINTER (DECL_NAME (parm))
845 : : : NULL, parm_type, sc->simdlen);
846 : : }
847 : : }
848 : :
849 : 7156 : if (sc->inbranch)
850 : : {
851 : 2231 : tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
852 : 2231 : tree mask_type;
853 : 2231 : if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
854 : 1605 : veclen = sc->vecsize_int;
855 : : else
856 : 626 : veclen = sc->vecsize_float;
857 : 2231 : if (known_eq (veclen, 0U))
858 : 0 : veclen = sc->simdlen;
859 : : else
860 : 4462 : veclen = exact_div (veclen,
861 : 4462 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type)));
862 : 2231 : if (multiple_p (veclen, sc->simdlen))
863 : 2113 : veclen = sc->simdlen;
864 : 2231 : if (sc->mask_mode != VOIDmode)
865 : 547 : mask_type
866 : 547 : = lang_hooks.types.type_for_mode (sc->mask_mode, 1);
867 : 1684 : else if (POINTER_TYPE_P (base_type))
868 : 19 : mask_type = build_vector_type (pointer_sized_int_node, veclen);
869 : : else
870 : 1665 : mask_type = build_vector_type (base_type, veclen);
871 : :
872 : 2231 : 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 : 2231 : sc->nargs++;
877 : 2231 : if (sc->mask_mode != VOIDmode)
878 : 547 : base_type = boolean_type_node;
879 : 2231 : if (node->definition)
880 : : {
881 : 1971 : sc->args[i].orig_arg
882 : 1971 : = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type);
883 : 1971 : if (sc->mask_mode == VOIDmode)
884 : 1489 : sc->args[i].simd_array
885 : 1489 : = create_tmp_simd_array ("mask", base_type, sc->simdlen);
886 : 482 : else if (k > 1)
887 : 1 : sc->args[i].simd_array
888 : 1 : = create_tmp_simd_array ("mask", mask_type, k);
889 : : else
890 : 481 : sc->args[i].simd_array = NULL_TREE;
891 : : }
892 : 2231 : sc->args[i].orig_type = base_type;
893 : 2231 : sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK;
894 : 2231 : sc->args[i].vector_type = mask_type;
895 : : /* Record the number of mask copies when that is difficult to
896 : : compute. */
897 : 2231 : if (sc->mask_mode != VOIDmode)
898 : 547 : sc->args[i].linear_step = k;
899 : : }
900 : :
901 : 7156 : if (!node->definition)
902 : : {
903 : 2684 : tree new_arg_types = NULL_TREE, new_reversed;
904 : 2684 : bool last_parm_void = false;
905 : 5368 : if (args.length () > 0 && args.last () == void_type_node)
906 : : last_parm_void = true;
907 : :
908 : 2684 : gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
909 : 6797 : for (i = 0; i < new_params.length (); i++)
910 : 4113 : new_arg_types = tree_cons (NULL_TREE, new_params[i], new_arg_types);
911 : 2684 : new_reversed = nreverse (new_arg_types);
912 : 2684 : if (last_parm_void)
913 : : {
914 : 2684 : if (new_reversed)
915 : 2684 : TREE_CHAIN (new_arg_types) = void_list_node;
916 : : else
917 : 0 : new_reversed = void_list_node;
918 : : }
919 : 2684 : TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed;
920 : : }
921 : 7156 : }
922 : :
923 : : /* Initialize and copy the function arguments in NODE to their
924 : : corresponding local simd arrays. Returns a fresh gimple_seq with
925 : : the instruction sequence generated. */
926 : :
927 : : static gimple_seq
928 : 4472 : simd_clone_init_simd_arrays (struct cgraph_node *node,
929 : : ipa_param_body_adjustments *adjustments)
930 : : {
931 : 4472 : gimple_seq seq = NULL;
932 : 4472 : unsigned i = 0, j = 0, k;
933 : :
934 : 4472 : for (tree arg = DECL_ARGUMENTS (node->decl);
935 : 14812 : arg;
936 : 10340 : arg = DECL_CHAIN (arg), i++, j++)
937 : : {
938 : 10340 : ipa_adjusted_param adj = (*adjustments->m_adj_params)[j];
939 : 14238 : if (adj.op == IPA_PARAM_OP_COPY
940 : 10340 : || POINTER_TYPE_P (TREE_TYPE (arg)))
941 : 8278 : continue;
942 : :
943 : 6442 : node->simdclone->args[i].vector_arg = arg;
944 : :
945 : 6442 : tree array = node->simdclone->args[i].simd_array;
946 : 6442 : if (node->simdclone->mask_mode != VOIDmode
947 : 1554 : && adj.param_prefix_index == IPA_PARAM_PREFIX_MASK)
948 : : {
949 : 482 : if (array == NULL_TREE)
950 : 481 : continue;
951 : 1 : unsigned int l
952 : 1 : = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array))));
953 : 5 : for (k = 0; k <= l; k++)
954 : : {
955 : 4 : if (k)
956 : : {
957 : 3 : arg = DECL_CHAIN (arg);
958 : 3 : j++;
959 : : }
960 : 4 : tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
961 : 4 : array, size_int (k), NULL, NULL);
962 : 4 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
963 : 4 : gimplify_and_add (t, &seq);
964 : : }
965 : 1 : continue;
966 : 1 : }
967 : 5960 : if (!VECTOR_TYPE_P (TREE_TYPE (arg))
968 : 5960 : || known_eq (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)),
969 : : node->simdclone->simdlen))
970 : : {
971 : 4515 : tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
972 : 4515 : tree ptr = build_fold_addr_expr (array);
973 : 4515 : tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
974 : : build_int_cst (ptype, 0));
975 : 4515 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
976 : 4515 : gimplify_and_add (t, &seq);
977 : : }
978 : : else
979 : : {
980 : 1445 : poly_uint64 simdlen = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg));
981 : 1445 : unsigned int times = vector_unroll_factor (node->simdclone->simdlen,
982 : : simdlen);
983 : 1445 : tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
984 : 4765 : for (k = 0; k < times; k++)
985 : : {
986 : 3320 : tree ptr = build_fold_addr_expr (array);
987 : 3320 : int elemsize;
988 : 3320 : if (k)
989 : : {
990 : 1875 : arg = DECL_CHAIN (arg);
991 : 1875 : j++;
992 : : }
993 : 3320 : tree elemtype = TREE_TYPE (TREE_TYPE (arg));
994 : 3320 : elemsize = GET_MODE_SIZE (SCALAR_TYPE_MODE (elemtype));
995 : 3320 : tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
996 : 3320 : build_int_cst (ptype, k * elemsize * simdlen));
997 : 3320 : t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
998 : 3320 : gimplify_and_add (t, &seq);
999 : : }
1000 : : }
1001 : : }
1002 : 4472 : return seq;
1003 : : }
1004 : :
1005 : : /* Callback info for ipa_simd_modify_stmt_ops below. */
1006 : :
1007 : : struct modify_stmt_info {
1008 : : ipa_param_body_adjustments *adjustments;
1009 : : gimple *stmt;
1010 : : gimple *after_stmt;
1011 : : /* True if the parent statement was modified by
1012 : : ipa_simd_modify_stmt_ops. */
1013 : : bool modified;
1014 : : };
1015 : :
1016 : : /* Callback for walk_gimple_op.
1017 : :
1018 : : Adjust operands from a given statement as specified in the
1019 : : adjustments vector in the callback data. */
1020 : :
1021 : : static tree
1022 : 130909 : ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
1023 : : {
1024 : 130909 : struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
1025 : 130909 : struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
1026 : 130909 : tree *orig_tp = tp;
1027 : 130909 : if (TREE_CODE (*tp) == ADDR_EXPR)
1028 : 9108 : tp = &TREE_OPERAND (*tp, 0);
1029 : :
1030 : 130909 : if (TREE_CODE (*tp) == BIT_FIELD_REF
1031 : 130909 : || TREE_CODE (*tp) == IMAGPART_EXPR
1032 : 130909 : || TREE_CODE (*tp) == REALPART_EXPR)
1033 : 0 : tp = &TREE_OPERAND (*tp, 0);
1034 : :
1035 : 130909 : tree repl = NULL_TREE;
1036 : 130909 : ipa_param_body_replacement *pbr = NULL;
1037 : :
1038 : 130909 : if (TREE_CODE (*tp) == PARM_DECL)
1039 : : {
1040 : 2084 : pbr = info->adjustments->get_expr_replacement (*tp, true);
1041 : 2084 : if (pbr)
1042 : 1304 : repl = pbr->repl;
1043 : : }
1044 : 128825 : else if (TYPE_P (*tp))
1045 : 0 : *walk_subtrees = 0;
1046 : :
1047 : 1304 : if (repl)
1048 : 1304 : repl = unshare_expr (repl);
1049 : : else
1050 : : {
1051 : 129605 : if (tp != orig_tp)
1052 : : {
1053 : 8376 : *walk_subtrees = 0;
1054 : 8376 : bool modified = info->modified;
1055 : 8376 : info->modified = false;
1056 : 8376 : walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset);
1057 : 8376 : if (!info->modified)
1058 : : {
1059 : 8192 : info->modified = modified;
1060 : 8192 : return NULL_TREE;
1061 : : }
1062 : 184 : info->modified = modified;
1063 : 184 : repl = *tp;
1064 : : }
1065 : : else
1066 : : return NULL_TREE;
1067 : : }
1068 : :
1069 : 1488 : if (tp != orig_tp)
1070 : : {
1071 : 916 : if (gimple_code (info->stmt) == GIMPLE_PHI
1072 : 48 : && pbr
1073 : 40 : && TREE_CODE (*orig_tp) == ADDR_EXPR
1074 : 40 : && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL
1075 : 956 : && pbr->dummy)
1076 : : {
1077 : 0 : gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME);
1078 : 0 : *orig_tp = pbr->dummy;
1079 : 0 : info->modified = true;
1080 : 0 : return NULL_TREE;
1081 : : }
1082 : :
1083 : 916 : repl = build_fold_addr_expr (repl);
1084 : 916 : gimple *stmt;
1085 : 916 : if (is_gimple_debug (info->stmt))
1086 : : {
1087 : 88 : tree vexpr = build_debug_expr_decl (TREE_TYPE (repl));
1088 : 88 : stmt = gimple_build_debug_source_bind (vexpr, repl, NULL);
1089 : 88 : repl = vexpr;
1090 : : }
1091 : : else
1092 : : {
1093 : 828 : stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
1094 : 828 : repl = gimple_assign_lhs (stmt);
1095 : : }
1096 : 916 : gimple_stmt_iterator gsi;
1097 : 916 : if (gimple_code (info->stmt) == GIMPLE_PHI)
1098 : : {
1099 : 48 : if (info->after_stmt)
1100 : 8 : gsi = gsi_for_stmt (info->after_stmt);
1101 : : else
1102 : 40 : gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
1103 : : /* Cache SSA_NAME for next time. */
1104 : 48 : if (pbr
1105 : 40 : && TREE_CODE (*orig_tp) == ADDR_EXPR
1106 : 88 : && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL)
1107 : : {
1108 : 40 : gcc_assert (!pbr->dummy);
1109 : 40 : pbr->dummy = repl;
1110 : : }
1111 : : }
1112 : : else
1113 : 868 : gsi = gsi_for_stmt (info->stmt);
1114 : 916 : if (info->after_stmt)
1115 : 8 : gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
1116 : : else
1117 : 908 : gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1118 : 916 : if (gimple_code (info->stmt) == GIMPLE_PHI)
1119 : 48 : info->after_stmt = stmt;
1120 : 916 : *orig_tp = repl;
1121 : : }
1122 : 572 : else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
1123 : : {
1124 : 0 : tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
1125 : 0 : *tp = vce;
1126 : : }
1127 : : else
1128 : 572 : *tp = repl;
1129 : :
1130 : 1488 : info->modified = true;
1131 : 1488 : return NULL_TREE;
1132 : : }
1133 : :
1134 : : /* Traverse the function body and perform all modifications as
1135 : : described in ADJUSTMENTS. At function return, ADJUSTMENTS will be
1136 : : modified such that the replacement/reduction value will now be an
1137 : : offset into the corresponding simd_array.
1138 : :
1139 : : This function will replace all function argument uses with their
1140 : : corresponding simd array elements, and ajust the return values
1141 : : accordingly. */
1142 : :
1143 : : static void
1144 : 4472 : ipa_simd_modify_function_body (struct cgraph_node *node,
1145 : : ipa_param_body_adjustments *adjustments,
1146 : : tree retval_array, tree iter)
1147 : : {
1148 : 4472 : basic_block bb;
1149 : 4472 : unsigned int i, j;
1150 : :
1151 : :
1152 : : /* Register replacements for every function argument use to an offset into
1153 : : the corresponding simd_array. */
1154 : 14812 : for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
1155 : : {
1156 : 16209 : if (!node->simdclone->args[i].vector_arg
1157 : 10340 : || (*adjustments->m_adj_params)[j].user_flag)
1158 : 5869 : continue;
1159 : :
1160 : 4471 : tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1161 : 4471 : tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
1162 : 4471 : tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
1163 : : iter, NULL_TREE, NULL_TREE);
1164 : 4471 : adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
1165 : :
1166 : 4471 : if (multiple_p (node->simdclone->simdlen, TYPE_VECTOR_SUBPARTS (vectype)))
1167 : 4471 : j += vector_unroll_factor (node->simdclone->simdlen,
1168 : 4471 : TYPE_VECTOR_SUBPARTS (vectype)) - 1;
1169 : : }
1170 : 4472 : adjustments->sort_replacements ();
1171 : :
1172 : 4472 : tree name;
1173 : 45967 : FOR_EACH_SSA_NAME (i, name, cfun)
1174 : : {
1175 : 41495 : tree base_var;
1176 : 41495 : if (SSA_NAME_VAR (name)
1177 : 23993 : && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
1178 : 7937 : && (base_var
1179 : 7937 : = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
1180 : : {
1181 : 4483 : if (SSA_NAME_IS_DEFAULT_DEF (name))
1182 : : {
1183 : 4051 : tree old_decl = SSA_NAME_VAR (name);
1184 : 4051 : bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1185 : 4051 : gimple_stmt_iterator gsi = gsi_after_labels (bb);
1186 : 4051 : tree repl = adjustments->lookup_replacement (old_decl, 0);
1187 : 4051 : gcc_checking_assert (repl);
1188 : 4051 : repl = unshare_expr (repl);
1189 : 4051 : set_ssa_default_def (cfun, old_decl, NULL_TREE);
1190 : 4051 : SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1191 : 4051 : SSA_NAME_IS_DEFAULT_DEF (name) = 0;
1192 : 4051 : gimple *stmt = gimple_build_assign (name, repl);
1193 : 4051 : gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1194 : : }
1195 : : else
1196 : 864 : SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
1197 : : }
1198 : : }
1199 : :
1200 : 4472 : struct modify_stmt_info info;
1201 : 4472 : info.adjustments = adjustments;
1202 : :
1203 : 19654 : FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
1204 : : {
1205 : 15182 : gimple_stmt_iterator gsi;
1206 : :
1207 : 17854 : for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1208 : : {
1209 : 2672 : gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
1210 : 2672 : int i, n = gimple_phi_num_args (phi);
1211 : 2672 : info.stmt = phi;
1212 : 2672 : info.after_stmt = NULL;
1213 : 2672 : struct walk_stmt_info wi;
1214 : 2672 : memset (&wi, 0, sizeof (wi));
1215 : 2672 : info.modified = false;
1216 : 2672 : wi.info = &info;
1217 : 8940 : for (i = 0; i < n; ++i)
1218 : : {
1219 : 6268 : int walk_subtrees = 1;
1220 : 6268 : tree arg = gimple_phi_arg_def (phi, i);
1221 : 6268 : tree op = arg;
1222 : 6268 : ipa_simd_modify_stmt_ops (&op, &walk_subtrees, &wi);
1223 : 6268 : if (op != arg)
1224 : : {
1225 : 40 : SET_PHI_ARG_DEF (phi, i, op);
1226 : 40 : gcc_assert (TREE_CODE (op) == SSA_NAME);
1227 : 40 : if (gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL)
1228 : 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
1229 : : }
1230 : : }
1231 : : }
1232 : :
1233 : 15182 : gsi = gsi_start_bb (bb);
1234 : 62531 : while (!gsi_end_p (gsi))
1235 : : {
1236 : 47349 : gimple *stmt = gsi_stmt (gsi);
1237 : 47349 : info.stmt = stmt;
1238 : 47349 : info.after_stmt = NULL;
1239 : 47349 : struct walk_stmt_info wi;
1240 : :
1241 : 47349 : memset (&wi, 0, sizeof (wi));
1242 : 47349 : info.modified = false;
1243 : 47349 : wi.info = &info;
1244 : 47349 : walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
1245 : :
1246 : 47349 : if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
1247 : : {
1248 : 4392 : tree retval = gimple_return_retval (return_stmt);
1249 : 4392 : edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
1250 : 4392 : e->flags |= EDGE_FALLTHRU;
1251 : 4392 : if (!retval)
1252 : : {
1253 : 720 : gsi_remove (&gsi, true);
1254 : 744 : continue;
1255 : : }
1256 : :
1257 : : /* Replace `return foo' with `retval_array[iter] = foo'. */
1258 : 3672 : tree ref = build4 (ARRAY_REF, TREE_TYPE (retval),
1259 : : retval_array, iter, NULL, NULL);
1260 : 3672 : stmt = gimple_build_assign (ref, retval);
1261 : 3672 : gsi_replace (&gsi, stmt, true);
1262 : 3672 : info.modified = true;
1263 : : }
1264 : :
1265 : 46629 : if (info.modified)
1266 : : {
1267 : 4792 : update_stmt (stmt);
1268 : : /* If the above changed the var of a debug bind into something
1269 : : different, remove the debug stmt. We could also for all the
1270 : : replaced parameters add VAR_DECLs for debug info purposes,
1271 : : add debug stmts for those to be the simd array accesses and
1272 : : replace debug stmt var operand with that var. Debugging of
1273 : : vectorized loops doesn't work too well, so don't bother for
1274 : : now. */
1275 : 4848 : if ((gimple_debug_bind_p (stmt)
1276 : 80 : && !DECL_P (gimple_debug_bind_get_var (stmt)))
1277 : 136 : || (gimple_debug_source_bind_p (stmt)
1278 : 0 : && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
1279 : : {
1280 : 24 : gsi_remove (&gsi, true);
1281 : 24 : continue;
1282 : : }
1283 : 4768 : if (maybe_clean_eh_stmt (stmt))
1284 : 0 : gimple_purge_dead_eh_edges (gimple_bb (stmt));
1285 : : }
1286 : 46605 : gsi_next (&gsi);
1287 : : }
1288 : : }
1289 : 4472 : }
1290 : :
1291 : : /* Helper function of simd_clone_adjust, return linear step addend
1292 : : of Ith argument. */
1293 : :
1294 : : static tree
1295 : 2071 : simd_clone_linear_addend (struct cgraph_node *node, unsigned int i,
1296 : : tree addtype, basic_block entry_bb)
1297 : : {
1298 : 2071 : tree ptype = NULL_TREE;
1299 : 2071 : switch (node->simdclone->args[i].arg_type)
1300 : : {
1301 : 1919 : case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
1302 : 1919 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
1303 : 1919 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1304 : 1919 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
1305 : 1919 : return build_int_cst (addtype, node->simdclone->args[i].linear_step);
1306 : 140 : case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
1307 : 140 : case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
1308 : 140 : ptype = TREE_TYPE (node->simdclone->args[i].orig_arg);
1309 : 140 : break;
1310 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1311 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1312 : 12 : ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg));
1313 : 12 : break;
1314 : 0 : default:
1315 : 0 : gcc_unreachable ();
1316 : : }
1317 : :
1318 : 152 : unsigned int idx = node->simdclone->args[i].linear_step;
1319 : 152 : tree arg = node->simdclone->args[idx].orig_arg;
1320 : 152 : gcc_assert (is_gimple_reg_type (TREE_TYPE (arg)));
1321 : 152 : gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1322 : 152 : gimple *g;
1323 : 152 : tree ret;
1324 : 152 : if (is_gimple_reg (arg))
1325 : 152 : ret = get_or_create_ssa_default_def (cfun, arg);
1326 : : else
1327 : : {
1328 : 0 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
1329 : 0 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1330 : 0 : ret = gimple_assign_lhs (g);
1331 : : }
1332 : 152 : if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
1333 : : {
1334 : 28 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))),
1335 : : build_simple_mem_ref (ret));
1336 : 28 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1337 : 28 : ret = gimple_assign_lhs (g);
1338 : : }
1339 : 152 : if (!useless_type_conversion_p (addtype, TREE_TYPE (ret)))
1340 : : {
1341 : 60 : g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret);
1342 : 60 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1343 : 60 : ret = gimple_assign_lhs (g);
1344 : : }
1345 : 152 : if (POINTER_TYPE_P (ptype))
1346 : : {
1347 : 60 : tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype));
1348 : 60 : if (size && TREE_CODE (size) == INTEGER_CST)
1349 : : {
1350 : 60 : g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR,
1351 : : ret, fold_convert (addtype, size));
1352 : 60 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1353 : 60 : ret = gimple_assign_lhs (g);
1354 : : }
1355 : : }
1356 : : return ret;
1357 : : }
1358 : :
1359 : : /* Adjust the argument types in NODE to their appropriate vector
1360 : : counterparts. */
1361 : :
1362 : : static void
1363 : 4472 : simd_clone_adjust (struct cgraph_node *node)
1364 : : {
1365 : 4472 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
1366 : :
1367 : 4472 : tree orig_rettype = TREE_TYPE (TREE_TYPE (node->decl));
1368 : 4472 : TREE_TYPE (node->decl) = build_distinct_type_copy (TREE_TYPE (node->decl));
1369 : 4472 : simd_clone_adjust_return_type (node);
1370 : 4472 : simd_clone_adjust_argument_types (node);
1371 : 4472 : targetm.simd_clone.adjust (node);
1372 : 4472 : tree retval = NULL_TREE;
1373 : 4472 : if (orig_rettype != void_type_node)
1374 : : {
1375 : 3728 : poly_uint64 veclen;
1376 : 3728 : if (INTEGRAL_TYPE_P (orig_rettype) || POINTER_TYPE_P (orig_rettype))
1377 : 2819 : veclen = node->simdclone->vecsize_int;
1378 : : else
1379 : 909 : veclen = node->simdclone->vecsize_float;
1380 : 3728 : if (known_eq (veclen, 0U))
1381 : 0 : veclen = node->simdclone->simdlen;
1382 : : else
1383 : 7456 : veclen = exact_div (veclen,
1384 : 7456 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (orig_rettype)));
1385 : 3728 : if (multiple_p (veclen, node->simdclone->simdlen))
1386 : 3521 : veclen = node->simdclone->simdlen;
1387 : :
1388 : 3728 : retval = DECL_RESULT (node->decl);
1389 : : /* Adjust the DECL_RESULT. */
1390 : 3728 : TREE_TYPE (retval) = TREE_TYPE (TREE_TYPE (node->decl));
1391 : 3728 : relayout_decl (retval);
1392 : :
1393 : 7456 : tree atype = build_array_type_nelts (orig_rettype,
1394 : 3728 : node->simdclone->simdlen);
1395 : 3728 : if (maybe_ne (veclen, node->simdclone->simdlen))
1396 : 207 : retval = build1 (VIEW_CONVERT_EXPR, atype, retval);
1397 : : else
1398 : : {
1399 : : /* Set up a SIMD array to use as the return value. */
1400 : 3521 : retval = create_tmp_var_raw (atype, "retval");
1401 : 3521 : gimple_add_tmp_var (retval);
1402 : : }
1403 : : }
1404 : :
1405 : 4472 : struct cgraph_simd_clone *sc = node->simdclone;
1406 : 4472 : vec<ipa_adjusted_param, va_gc> *new_params = NULL;
1407 : 4472 : vec_safe_reserve (new_params, sc->nargs);
1408 : 4472 : unsigned i, j, k;
1409 : 14812 : for (i = 0; i < sc->nargs; ++i)
1410 : : {
1411 : 10340 : ipa_adjusted_param adj;
1412 : 10340 : memset (&adj, 0, sizeof (adj));
1413 : 10340 : poly_uint64 veclen;
1414 : 10340 : tree elem_type;
1415 : :
1416 : 10340 : adj.base_index = i;
1417 : 10340 : adj.prev_clone_index = i;
1418 : 10340 : switch (sc->args[i].arg_type)
1419 : : {
1420 : 3886 : default:
1421 : : /* No adjustment necessary for scalar arguments. */
1422 : 3886 : adj.op = IPA_PARAM_OP_COPY;
1423 : 3886 : break;
1424 : 12 : case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
1425 : 12 : adj.op = IPA_PARAM_OP_COPY;
1426 : 12 : break;
1427 : 6442 : case SIMD_CLONE_ARG_TYPE_MASK:
1428 : 6442 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
1429 : 6442 : case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
1430 : 6442 : case SIMD_CLONE_ARG_TYPE_VECTOR:
1431 : 6442 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK
1432 : 1971 : && sc->mask_mode != VOIDmode)
1433 : 482 : elem_type = simd_clone_compute_base_data_type (sc->origin, sc);
1434 : : else
1435 : 5960 : elem_type = TREE_TYPE (sc->args[i].vector_type);
1436 : 6442 : if (INTEGRAL_TYPE_P (elem_type) || POINTER_TYPE_P (elem_type))
1437 : 4738 : veclen = sc->vecsize_int;
1438 : : else
1439 : 1704 : veclen = sc->vecsize_float;
1440 : 6442 : if (known_eq (veclen, 0U))
1441 : 0 : veclen = sc->simdlen;
1442 : : else
1443 : 6442 : veclen
1444 : 6442 : = exact_div (veclen,
1445 : 12884 : GET_MODE_BITSIZE (SCALAR_TYPE_MODE (elem_type)));
1446 : 6442 : if (multiple_p (veclen, sc->simdlen))
1447 : 4996 : veclen = sc->simdlen;
1448 : 6442 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
1449 : : {
1450 : 1971 : adj.user_flag = 1;
1451 : 1971 : adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
1452 : : }
1453 : : else
1454 : 4471 : adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
1455 : 6442 : adj.op = IPA_PARAM_OP_NEW;
1456 : 6442 : adj.type = sc->args[i].vector_type;
1457 : 6442 : k = vector_unroll_factor (sc->simdlen, veclen);
1458 : 8320 : for (j = 1; j < k; j++)
1459 : : {
1460 : 1878 : vec_safe_push (new_params, adj);
1461 : 1878 : if (j == 1)
1462 : : {
1463 : 1446 : memset (&adj, 0, sizeof (adj));
1464 : 1446 : adj.op = IPA_PARAM_OP_NEW;
1465 : 1446 : adj.user_flag = 1;
1466 : 1446 : if (sc->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
1467 : 95 : adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
1468 : : else
1469 : 1351 : adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
1470 : 1446 : adj.base_index = i;
1471 : 1446 : adj.prev_clone_index = i;
1472 : 1446 : adj.type = sc->args[i].vector_type;
1473 : : }
1474 : : }
1475 : : }
1476 : 10340 : vec_safe_push (new_params, adj);
1477 : : }
1478 : 4472 : ipa_param_body_adjustments *adjustments
1479 : 4472 : = new ipa_param_body_adjustments (new_params, node->decl);
1480 : 4472 : adjustments->modify_formal_parameters ();
1481 : :
1482 : 4472 : push_gimplify_context ();
1483 : :
1484 : 4472 : gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments);
1485 : :
1486 : : /* Adjust all uses of vector arguments accordingly. Adjust all
1487 : : return values accordingly. */
1488 : 4472 : tree iter = create_tmp_var (unsigned_type_node, "iter");
1489 : 4472 : tree iter1 = make_ssa_name (iter);
1490 : 4472 : tree iter2 = NULL_TREE;
1491 : 4472 : ipa_simd_modify_function_body (node, adjustments, retval, iter1);
1492 : 4472 : delete adjustments;
1493 : :
1494 : : /* Initialize the iteration variable. */
1495 : 4472 : basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1496 : 4472 : basic_block body_bb = split_block_after_labels (entry_bb)->dest;
1497 : 4472 : gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
1498 : : /* Insert the SIMD array and iv initialization at function
1499 : : entry. */
1500 : 4472 : gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
1501 : :
1502 : 4472 : pop_gimplify_context (NULL);
1503 : :
1504 : 4472 : gimple *g;
1505 : 4472 : basic_block incr_bb = NULL;
1506 : 4472 : class loop *loop = NULL;
1507 : :
1508 : : /* Create a new BB right before the original exit BB, to hold the
1509 : : iteration increment and the condition/branch. */
1510 : 4472 : if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1511 : : {
1512 : 4352 : basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
1513 : 4352 : incr_bb = create_empty_bb (orig_exit);
1514 : 4352 : incr_bb->count = profile_count::zero ();
1515 : 4352 : add_bb_to_loop (incr_bb, body_bb->loop_father);
1516 : 13096 : while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
1517 : : {
1518 : 4392 : edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1519 : 4392 : redirect_edge_succ (e, incr_bb);
1520 : 4392 : incr_bb->count += e->count ();
1521 : : }
1522 : : }
1523 : 120 : else if (node->simdclone->inbranch)
1524 : : {
1525 : 60 : incr_bb = create_empty_bb (entry_bb);
1526 : 60 : incr_bb->count = profile_count::zero ();
1527 : 60 : add_bb_to_loop (incr_bb, body_bb->loop_father);
1528 : : }
1529 : :
1530 : 60 : if (incr_bb)
1531 : : {
1532 : 4412 : make_single_succ_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
1533 : 4412 : gsi = gsi_last_bb (incr_bb);
1534 : 4412 : iter2 = make_ssa_name (iter);
1535 : 4412 : g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
1536 : : build_int_cst (unsigned_type_node, 1));
1537 : 4412 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1538 : :
1539 : : /* Mostly annotate the loop for the vectorizer (the rest is done
1540 : : below). */
1541 : 4412 : loop = alloc_loop ();
1542 : 4412 : cfun->has_force_vectorize_loops = true;
1543 : : /* We can assert that safelen is the 'minimum' simdlen. */
1544 : 4412 : loop->safelen = constant_lower_bound (node->simdclone->simdlen);
1545 : 4412 : loop->force_vectorize = true;
1546 : 4412 : loop->header = body_bb;
1547 : : }
1548 : :
1549 : : /* Branch around the body if the mask applies. */
1550 : 4472 : if (node->simdclone->inbranch)
1551 : : {
1552 : 1971 : gsi = gsi_last_bb (loop->header);
1553 : 1971 : tree mask_array
1554 : 1971 : = node->simdclone->args[node->simdclone->nargs - 1].simd_array;
1555 : 1971 : tree mask;
1556 : 1971 : if (node->simdclone->mask_mode != VOIDmode)
1557 : : {
1558 : 482 : tree shift_cnt;
1559 : 482 : if (mask_array == NULL_TREE)
1560 : : {
1561 : 481 : tree arg = node->simdclone->args[node->simdclone->nargs
1562 : : - 1].vector_arg;
1563 : 481 : mask = get_or_create_ssa_default_def (cfun, arg);
1564 : 481 : shift_cnt = iter1;
1565 : : }
1566 : : else
1567 : : {
1568 : 1 : tree maskt = TREE_TYPE (mask_array);
1569 : 1 : int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt)));
1570 : : /* For now, c must be constant here. */
1571 : 1 : c = exact_div (node->simdclone->simdlen, c + 1).to_constant ();
1572 : 1 : int s = exact_log2 (c);
1573 : 1 : gcc_assert (s > 0);
1574 : 1 : c--;
1575 : 1 : tree idx = make_ssa_name (TREE_TYPE (iter1));
1576 : 1 : g = gimple_build_assign (idx, RSHIFT_EXPR, iter1,
1577 : 1 : build_int_cst (NULL_TREE, s));
1578 : 1 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1579 : 1 : mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1580 : 1 : tree aref = build4 (ARRAY_REF,
1581 : 1 : TREE_TYPE (TREE_TYPE (mask_array)),
1582 : : mask_array, idx, NULL, NULL);
1583 : 1 : g = gimple_build_assign (mask, aref);
1584 : 1 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1585 : 1 : shift_cnt = make_ssa_name (TREE_TYPE (iter1));
1586 : 1 : g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1,
1587 : 1 : build_int_cst (TREE_TYPE (iter1), c));
1588 : 1 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1589 : : }
1590 : 482 : tree shift_cnt_conv = shift_cnt;
1591 : 482 : if (!useless_type_conversion_p (TREE_TYPE (mask),
1592 : 482 : TREE_TYPE (shift_cnt)))
1593 : : {
1594 : 9 : shift_cnt_conv = make_ssa_name (TREE_TYPE (mask));
1595 : 9 : g = gimple_build_assign (shift_cnt_conv, NOP_EXPR, shift_cnt);
1596 : 9 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1597 : : }
1598 : 482 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1599 : : RSHIFT_EXPR, mask, shift_cnt_conv);
1600 : 482 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1601 : 482 : mask = gimple_assign_lhs (g);
1602 : 482 : g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
1603 : : BIT_AND_EXPR, mask,
1604 : 482 : build_one_cst (TREE_TYPE (mask)));
1605 : 482 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1606 : 482 : mask = gimple_assign_lhs (g);
1607 : : }
1608 : : else
1609 : : {
1610 : 1489 : mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
1611 : 1489 : tree aref = build4 (ARRAY_REF,
1612 : 1489 : TREE_TYPE (TREE_TYPE (mask_array)),
1613 : : mask_array, iter1, NULL, NULL);
1614 : 1489 : g = gimple_build_assign (mask, aref);
1615 : 1489 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1616 : 1489 : int bitsize = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (aref)));
1617 : 1489 : if (!INTEGRAL_TYPE_P (TREE_TYPE (aref)))
1618 : : {
1619 : 364 : aref = build1 (VIEW_CONVERT_EXPR,
1620 : : build_nonstandard_integer_type (bitsize, 0),
1621 : : mask);
1622 : 364 : mask = make_ssa_name (TREE_TYPE (aref));
1623 : 364 : g = gimple_build_assign (mask, aref);
1624 : 364 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1625 : : }
1626 : : }
1627 : :
1628 : 1971 : g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)),
1629 : : NULL, NULL);
1630 : 1971 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1631 : 1971 : edge e = make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE);
1632 : 1971 : e->probability = profile_probability::unlikely ().guessed ();
1633 : 1971 : incr_bb->count += e->count ();
1634 : 1971 : edge fallthru = FALLTHRU_EDGE (loop->header);
1635 : 1971 : fallthru->flags = EDGE_FALSE_VALUE;
1636 : 1971 : fallthru->probability = profile_probability::likely ().guessed ();
1637 : : }
1638 : :
1639 : 4472 : basic_block latch_bb = NULL;
1640 : 4472 : basic_block new_exit_bb = NULL;
1641 : :
1642 : : /* Generate the condition. */
1643 : 4472 : if (incr_bb)
1644 : : {
1645 : 4412 : gsi = gsi_last_bb (incr_bb);
1646 : 4412 : g = gimple_build_cond (LT_EXPR, iter2,
1647 : : build_int_cst (unsigned_type_node,
1648 : 4412 : node->simdclone->simdlen),
1649 : : NULL, NULL);
1650 : 4412 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1651 : 4412 : edge e = split_block (incr_bb, gsi_stmt (gsi));
1652 : 4412 : latch_bb = e->dest;
1653 : 4412 : new_exit_bb = split_block_after_labels (latch_bb)->dest;
1654 : 4412 : loop->latch = latch_bb;
1655 : :
1656 : 4412 : redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
1657 : :
1658 : 4412 : edge new_e = make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
1659 : :
1660 : : /* FIXME: Do we need to distribute probabilities for the conditional? */
1661 : 4412 : new_e->probability = profile_probability::guessed_never ();
1662 : : /* The successor of incr_bb is already pointing to latch_bb; just
1663 : : change the flags.
1664 : : make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE); */
1665 : 4412 : FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
1666 : : }
1667 : :
1668 : 4472 : gphi *phi = create_phi_node (iter1, body_bb);
1669 : 4472 : edge preheader_edge = find_edge (entry_bb, body_bb);
1670 : 4472 : edge latch_edge = NULL;
1671 : 4472 : add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
1672 : : UNKNOWN_LOCATION);
1673 : 4472 : if (incr_bb)
1674 : : {
1675 : 4412 : latch_edge = single_succ_edge (latch_bb);
1676 : 4412 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1677 : :
1678 : : /* Generate the new return. */
1679 : 4412 : gsi = gsi_last_bb (new_exit_bb);
1680 : 4412 : if (retval
1681 : 3716 : && TREE_CODE (retval) == VIEW_CONVERT_EXPR
1682 : 4619 : && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
1683 : 207 : retval = TREE_OPERAND (retval, 0);
1684 : 4205 : else if (retval)
1685 : : {
1686 : 3509 : retval = build1 (VIEW_CONVERT_EXPR,
1687 : 3509 : TREE_TYPE (TREE_TYPE (node->decl)),
1688 : : retval);
1689 : 3509 : retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
1690 : : false, GSI_CONTINUE_LINKING);
1691 : : }
1692 : 4412 : g = gimple_build_return (retval);
1693 : 4412 : gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1694 : : }
1695 : :
1696 : : /* Handle aligned clauses by replacing default defs of the aligned
1697 : : uniform args with __builtin_assume_aligned (arg_N(D), alignment)
1698 : : lhs. Handle linear by adding PHIs. */
1699 : 14812 : for (unsigned i = 0; i < node->simdclone->nargs; i++)
1700 : 10340 : if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1701 : 10340 : && (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg)
1702 : 1523 : || !is_gimple_reg_type
1703 : 1523 : (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1704 : : {
1705 : 236 : tree orig_arg = node->simdclone->args[i].orig_arg;
1706 : 236 : if (is_gimple_reg_type (TREE_TYPE (orig_arg)))
1707 : 208 : iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1708 : : else
1709 : : {
1710 : 28 : iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg));
1711 : 28 : gimple_add_tmp_var (iter1);
1712 : : }
1713 : 236 : gsi = gsi_after_labels (entry_bb);
1714 : 236 : g = gimple_build_assign (iter1, orig_arg);
1715 : 236 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1716 : 236 : gsi = gsi_after_labels (body_bb);
1717 : 236 : g = gimple_build_assign (orig_arg, iter1);
1718 : 236 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1719 : : }
1720 : 10104 : else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
1721 : 1495 : && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg)
1722 : 276 : && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1723 : : == REFERENCE_TYPE
1724 : 10364 : && TREE_ADDRESSABLE
1725 : : (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg))))
1726 : : {
1727 : 52 : tree orig_arg = node->simdclone->args[i].orig_arg;
1728 : 52 : tree def = ssa_default_def (cfun, orig_arg);
1729 : 52 : if (def && !has_zero_uses (def))
1730 : : {
1731 : 52 : iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg)));
1732 : 52 : gimple_add_tmp_var (iter1);
1733 : 52 : gsi = gsi_after_labels (entry_bb);
1734 : 52 : g = gimple_build_assign (iter1, build_simple_mem_ref (def));
1735 : 52 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1736 : 52 : gsi = gsi_after_labels (body_bb);
1737 : 52 : g = gimple_build_assign (build_simple_mem_ref (def), iter1);
1738 : 52 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1739 : : }
1740 : : }
1741 : 10052 : else if (node->simdclone->args[i].alignment
1742 : 364 : && node->simdclone->args[i].arg_type
1743 : : == SIMD_CLONE_ARG_TYPE_UNIFORM
1744 : 192 : && (node->simdclone->args[i].alignment
1745 : 192 : & (node->simdclone->args[i].alignment - 1)) == 0
1746 : 10244 : && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
1747 : : == POINTER_TYPE)
1748 : : {
1749 : 192 : unsigned int alignment = node->simdclone->args[i].alignment;
1750 : 192 : tree orig_arg = node->simdclone->args[i].orig_arg;
1751 : 192 : tree def = ssa_default_def (cfun, orig_arg);
1752 : 192 : if (def && !has_zero_uses (def))
1753 : : {
1754 : 184 : tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
1755 : 184 : gimple_seq seq = NULL;
1756 : 184 : bool need_cvt = false;
1757 : 184 : gcall *call
1758 : 184 : = gimple_build_call (fn, 2, def, size_int (alignment));
1759 : 184 : g = call;
1760 : 184 : if (!useless_type_conversion_p (TREE_TYPE (orig_arg),
1761 : : ptr_type_node))
1762 : 0 : need_cvt = true;
1763 : 0 : tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg);
1764 : 184 : gimple_call_set_lhs (g, t);
1765 : 184 : gimple_seq_add_stmt_without_update (&seq, g);
1766 : 184 : if (need_cvt)
1767 : : {
1768 : 0 : t = make_ssa_name (orig_arg);
1769 : 0 : g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g));
1770 : 0 : gimple_seq_add_stmt_without_update (&seq, g);
1771 : : }
1772 : 184 : gsi_insert_seq_on_edge_immediate
1773 : 184 : (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
1774 : :
1775 : 184 : entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
1776 : 184 : node->create_edge (cgraph_node::get_create (fn),
1777 : : call, entry_bb->count);
1778 : :
1779 : 184 : imm_use_iterator iter;
1780 : 184 : use_operand_p use_p;
1781 : 184 : gimple *use_stmt;
1782 : 184 : tree repl = gimple_get_lhs (g);
1783 : 736 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1784 : 368 : if (is_gimple_debug (use_stmt) || use_stmt == call)
1785 : 184 : continue;
1786 : : else
1787 : 552 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1788 : 368 : SET_USE (use_p, repl);
1789 : : }
1790 : : }
1791 : 9860 : else if ((node->simdclone->args[i].arg_type
1792 : : == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
1793 : 8337 : || (node->simdclone->args[i].arg_type
1794 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
1795 : 8005 : || (node->simdclone->args[i].arg_type
1796 : : == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP)
1797 : 7893 : || (node->simdclone->args[i].arg_type
1798 : : == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP))
1799 : : {
1800 : 1995 : tree orig_arg = node->simdclone->args[i].orig_arg;
1801 : 1995 : gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1802 : : || POINTER_TYPE_P (TREE_TYPE (orig_arg)));
1803 : 1995 : tree def = NULL_TREE;
1804 : 1995 : if (TREE_ADDRESSABLE (orig_arg))
1805 : : {
1806 : 100 : def = make_ssa_name (TREE_TYPE (orig_arg));
1807 : 100 : iter1 = make_ssa_name (TREE_TYPE (orig_arg));
1808 : 100 : if (incr_bb)
1809 : 88 : iter2 = make_ssa_name (TREE_TYPE (orig_arg));
1810 : 100 : gsi = gsi_after_labels (entry_bb);
1811 : 100 : g = gimple_build_assign (def, orig_arg);
1812 : 100 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1813 : : }
1814 : : else
1815 : : {
1816 : 1895 : def = ssa_default_def (cfun, orig_arg);
1817 : 1895 : if (!def || has_zero_uses (def))
1818 : : def = NULL_TREE;
1819 : : else
1820 : : {
1821 : 1847 : iter1 = make_ssa_name (orig_arg);
1822 : 1847 : if (incr_bb)
1823 : 1823 : iter2 = make_ssa_name (orig_arg);
1824 : : }
1825 : : }
1826 : 1947 : if (def)
1827 : : {
1828 : 1947 : phi = create_phi_node (iter1, body_bb);
1829 : 1947 : add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
1830 : 1947 : if (incr_bb)
1831 : : {
1832 : 1911 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1833 : 3822 : enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1834 : 1911 : ? PLUS_EXPR : POINTER_PLUS_EXPR;
1835 : 3822 : tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
1836 : 3822 : ? TREE_TYPE (orig_arg) : sizetype;
1837 : 1911 : tree addcst = simd_clone_linear_addend (node, i, addtype,
1838 : : entry_bb);
1839 : 1911 : gsi = gsi_last_bb (incr_bb);
1840 : 1911 : g = gimple_build_assign (iter2, code, iter1, addcst);
1841 : 1911 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1842 : : }
1843 : :
1844 : 1947 : imm_use_iterator iter;
1845 : 1947 : use_operand_p use_p;
1846 : 1947 : gimple *use_stmt;
1847 : 1947 : if (TREE_ADDRESSABLE (orig_arg))
1848 : : {
1849 : 100 : gsi = gsi_after_labels (body_bb);
1850 : 100 : g = gimple_build_assign (orig_arg, iter1);
1851 : 100 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
1852 : : }
1853 : : else
1854 : 7648 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1855 : 3954 : if (use_stmt == phi)
1856 : 1847 : continue;
1857 : : else
1858 : 6321 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1859 : 3954 : SET_USE (use_p, iter1);
1860 : : }
1861 : : }
1862 : 7865 : else if (node->simdclone->args[i].arg_type
1863 : : == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP
1864 : 7865 : || (node->simdclone->args[i].arg_type
1865 : : == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP))
1866 : : {
1867 : 172 : tree orig_arg = node->simdclone->args[i].orig_arg;
1868 : 172 : tree def = ssa_default_def (cfun, orig_arg);
1869 : 172 : gcc_assert (!TREE_ADDRESSABLE (orig_arg)
1870 : : && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE);
1871 : 172 : if (def && !has_zero_uses (def))
1872 : : {
1873 : 172 : tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
1874 : 172 : iter1 = make_ssa_name (orig_arg);
1875 : 172 : if (incr_bb)
1876 : 160 : iter2 = make_ssa_name (orig_arg);
1877 : 172 : tree iter3 = make_ssa_name (rtype);
1878 : 172 : tree iter4 = make_ssa_name (rtype);
1879 : 172 : tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
1880 : 172 : gsi = gsi_after_labels (entry_bb);
1881 : 172 : gimple *load
1882 : 172 : = gimple_build_assign (iter3, build_simple_mem_ref (def));
1883 : 172 : gsi_insert_before (&gsi, load, GSI_NEW_STMT);
1884 : :
1885 : 172 : tree array = node->simdclone->args[i].simd_array;
1886 : 172 : TREE_ADDRESSABLE (array) = 1;
1887 : 172 : tree ptr = build_fold_addr_expr (array);
1888 : 172 : phi = create_phi_node (iter1, body_bb);
1889 : 172 : add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
1890 : 172 : if (incr_bb)
1891 : : {
1892 : 160 : add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
1893 : 160 : g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
1894 : 160 : TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
1895 : 160 : gsi = gsi_last_bb (incr_bb);
1896 : 160 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1897 : : }
1898 : :
1899 : 172 : phi = create_phi_node (iter4, body_bb);
1900 : 172 : add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
1901 : 172 : if (incr_bb)
1902 : : {
1903 : 160 : add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
1904 : 320 : enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1905 : 160 : ? PLUS_EXPR : POINTER_PLUS_EXPR;
1906 : 320 : tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
1907 : 320 : ? TREE_TYPE (iter3) : sizetype;
1908 : 160 : tree addcst = simd_clone_linear_addend (node, i, addtype,
1909 : : entry_bb);
1910 : 160 : g = gimple_build_assign (iter5, code, iter4, addcst);
1911 : 160 : gsi = gsi_last_bb (incr_bb);
1912 : 160 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1913 : : }
1914 : :
1915 : 172 : g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
1916 : 172 : gsi = gsi_after_labels (body_bb);
1917 : 172 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1918 : :
1919 : 172 : imm_use_iterator iter;
1920 : 172 : use_operand_p use_p;
1921 : 172 : gimple *use_stmt;
1922 : 848 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
1923 : 504 : if (use_stmt == load)
1924 : 172 : continue;
1925 : : else
1926 : 996 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1927 : 332 : SET_USE (use_p, iter1);
1928 : :
1929 : 172 : if (!TYPE_READONLY (rtype) && incr_bb)
1930 : : {
1931 : 112 : tree v = make_ssa_name (rtype);
1932 : 112 : tree aref = build4 (ARRAY_REF, rtype, array,
1933 : : size_zero_node, NULL_TREE,
1934 : : NULL_TREE);
1935 : 112 : gsi = gsi_after_labels (new_exit_bb);
1936 : 112 : g = gimple_build_assign (v, aref);
1937 : 112 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1938 : 112 : g = gimple_build_assign (build_simple_mem_ref (def), v);
1939 : 112 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1940 : : }
1941 : : }
1942 : : }
1943 : :
1944 : 4472 : calculate_dominance_info (CDI_DOMINATORS);
1945 : 4472 : if (loop)
1946 : 4412 : add_loop (loop, loop->header->loop_father);
1947 : 4472 : update_ssa (TODO_update_ssa);
1948 : :
1949 : 4472 : pop_cfun ();
1950 : 4472 : }
1951 : :
1952 : : /* If the function in NODE is tagged as an elemental SIMD function,
1953 : : create the appropriate SIMD clones. */
1954 : :
1955 : : void
1956 : 4668215 : expand_simd_clones (struct cgraph_node *node)
1957 : : {
1958 : 4668215 : tree attr;
1959 : 4668215 : bool explicit_p = true;
1960 : :
1961 : 4668215 : if (node->inlined_to
1962 : 4668215 : || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
1963 : 1543710 : return;
1964 : :
1965 : 3124505 : attr = lookup_attribute ("omp declare simd",
1966 : 3124505 : DECL_ATTRIBUTES (node->decl));
1967 : :
1968 : : /* See if we can add an "omp declare simd" directive implicitly
1969 : : before giving up. */
1970 : : /* FIXME: OpenACC "#pragma acc routine" translates into
1971 : : "omp declare target", but appears also to have some other effects
1972 : : that conflict with generating SIMD clones, causing ICEs. So don't
1973 : : do this if we've got OpenACC instead of OpenMP. */
1974 : 3124505 : if (attr == NULL_TREE
1975 : : #ifdef ACCEL_COMPILER
1976 : : && (flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_ANY
1977 : : || flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_NOHOST)
1978 : : #else
1979 : 3123248 : && (flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_ANY
1980 : 3123177 : || flag_openmp_target_simd_clone == OMP_TARGET_SIMD_CLONE_HOST)
1981 : : #endif
1982 : 71 : && !oacc_get_fn_attrib (node->decl)
1983 : 3124576 : && ok_for_auto_simd_clone (node))
1984 : : {
1985 : 4 : attr = tree_cons (get_identifier ("omp declare simd"), NULL,
1986 : 4 : DECL_ATTRIBUTES (node->decl));
1987 : 4 : DECL_ATTRIBUTES (node->decl) = attr;
1988 : 4 : explicit_p = false;
1989 : : }
1990 : :
1991 : 3124505 : if (attr == NULL_TREE)
1992 : : return;
1993 : :
1994 : : /* Ignore
1995 : : #pragma omp declare simd
1996 : : extern int foo ();
1997 : : in C, there we don't know the argument types at all. */
1998 : 1261 : if (!node->definition
1999 : 1261 : && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE)
2000 : : return;
2001 : :
2002 : : /* Call this before creating clone_info, as it might ggc_collect. */
2003 : 1261 : if (node->definition && node->has_gimple_body_p ())
2004 : 661 : node->get_body ();
2005 : :
2006 : 1466 : do
2007 : : {
2008 : : /* Start with parsing the "omp declare simd" attribute(s). */
2009 : 1466 : bool inbranch_clause_specified;
2010 : 1466 : struct cgraph_simd_clone *clone_info
2011 : 1466 : = simd_clone_clauses_extract (node, TREE_VALUE (attr),
2012 : : &inbranch_clause_specified);
2013 : 1466 : if (clone_info == NULL)
2014 : 8 : continue;
2015 : :
2016 : 1465 : poly_uint64 orig_simdlen = clone_info->simdlen;
2017 : 1465 : tree base_type = simd_clone_compute_base_data_type (node, clone_info);
2018 : :
2019 : : /* The target can return 0 (no simd clones should be created),
2020 : : 1 (just one ISA of simd clones should be created) or higher
2021 : : count of ISA variants. In that case, clone_info is initialized
2022 : : for the first ISA variant. */
2023 : 1465 : int count
2024 : 1465 : = targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info,
2025 : : base_type, 0,
2026 : : explicit_p);
2027 : 1465 : if (count == 0)
2028 : 7 : continue;
2029 : :
2030 : : /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED,
2031 : : also create one inbranch and one !inbranch clone of it. */
2032 : 12690 : for (int i = 0; i < count * 2; i++)
2033 : : {
2034 : 11232 : struct cgraph_simd_clone *clone = clone_info;
2035 : 11232 : if (inbranch_clause_specified && (i & 1) != 0)
2036 : 3682 : continue;
2037 : :
2038 : 7550 : if (i != 0)
2039 : : {
2040 : 12184 : clone = simd_clone_struct_alloc (clone_info->nargs
2041 : 6092 : + ((i & 1) != 0));
2042 : 6092 : simd_clone_struct_copy (clone, clone_info);
2043 : : /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen
2044 : : and simd_clone_adjust_argument_types did to the first
2045 : : clone's info. */
2046 : 6092 : clone->nargs -= clone_info->inbranch;
2047 : 6092 : clone->simdlen = orig_simdlen;
2048 : : /* And call the target hook again to get the right ISA. */
2049 : 6092 : targetm.simd_clone.compute_vecsize_and_simdlen (node, clone,
2050 : : base_type,
2051 : : i / 2,
2052 : : explicit_p);
2053 : 6092 : if ((i & 1) != 0)
2054 : 1934 : clone->inbranch = 1;
2055 : : }
2056 : :
2057 : : /* simd_clone_mangle might fail if such a clone has been created
2058 : : already. */
2059 : 7550 : tree id = simd_clone_mangle (node, clone);
2060 : 7550 : if (id == NULL_TREE)
2061 : : {
2062 : 394 : if (i == 0)
2063 : 74 : clone->nargs += clone->inbranch;
2064 : 394 : continue;
2065 : : }
2066 : :
2067 : : /* Only when we are sure we want to create the clone actually
2068 : : clone the function (or definitions) or create another
2069 : : extern FUNCTION_DECL (for prototypes without definitions). */
2070 : 7156 : struct cgraph_node *n = simd_clone_create (node, !explicit_p);
2071 : 7156 : if (n == NULL)
2072 : : {
2073 : 0 : if (i == 0)
2074 : 0 : clone->nargs += clone->inbranch;
2075 : 0 : continue;
2076 : : }
2077 : :
2078 : 7156 : n->simdclone = clone;
2079 : 7156 : clone->origin = node;
2080 : 7156 : clone->next_clone = NULL;
2081 : 7156 : if (node->simd_clones == NULL)
2082 : : {
2083 : 1253 : clone->prev_clone = n;
2084 : 1253 : node->simd_clones = n;
2085 : : }
2086 : : else
2087 : : {
2088 : 5903 : clone->prev_clone = node->simd_clones->simdclone->prev_clone;
2089 : 5903 : clone->prev_clone->simdclone->next_clone = n;
2090 : 5903 : node->simd_clones->simdclone->prev_clone = n;
2091 : : }
2092 : 7156 : symtab->change_decl_assembler_name (n->decl, id);
2093 : : /* And finally adjust the return type, parameters and for
2094 : : definitions also function body. */
2095 : 7156 : if (node->definition)
2096 : 4472 : simd_clone_adjust (n);
2097 : : else
2098 : : {
2099 : 2684 : TREE_TYPE (n->decl)
2100 : 2684 : = build_distinct_type_copy (TREE_TYPE (n->decl));
2101 : 2684 : simd_clone_adjust_return_type (n);
2102 : 2684 : simd_clone_adjust_argument_types (n);
2103 : 2684 : targetm.simd_clone.adjust (n);
2104 : : }
2105 : 7156 : if (dump_file)
2106 : 8 : fprintf (dump_file, "\nGenerated %s clone %s\n",
2107 : 8 : (TREE_PUBLIC (n->decl) ? "global" : "local"),
2108 : 8 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
2109 : : }
2110 : : }
2111 : 1466 : while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
2112 : : }
2113 : :
2114 : : /* Entry point for IPA simd clone creation pass. */
2115 : :
2116 : : static unsigned int
2117 : 231584 : ipa_omp_simd_clone (void)
2118 : : {
2119 : 231584 : struct cgraph_node *node;
2120 : 9799594 : FOR_EACH_FUNCTION (node)
2121 : 4668213 : expand_simd_clones (node);
2122 : 231584 : return 0;
2123 : : }
2124 : :
2125 : : namespace {
2126 : :
2127 : : const pass_data pass_data_omp_simd_clone =
2128 : : {
2129 : : SIMPLE_IPA_PASS, /* type */
2130 : : "simdclone", /* name */
2131 : : OPTGROUP_OMP, /* optinfo_flags */
2132 : : TV_NONE, /* tv_id */
2133 : : ( PROP_ssa | PROP_cfg ), /* properties_required */
2134 : : 0, /* properties_provided */
2135 : : 0, /* properties_destroyed */
2136 : : 0, /* todo_flags_start */
2137 : : 0, /* todo_flags_finish */
2138 : : };
2139 : :
2140 : : class pass_omp_simd_clone : public simple_ipa_opt_pass
2141 : : {
2142 : : public:
2143 : 289302 : pass_omp_simd_clone(gcc::context *ctxt)
2144 : 578604 : : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt)
2145 : : {}
2146 : :
2147 : : /* opt_pass methods: */
2148 : : bool gate (function *) final override;
2149 : 231584 : unsigned int execute (function *) final override
2150 : : {
2151 : 231584 : return ipa_omp_simd_clone ();
2152 : : }
2153 : : };
2154 : :
2155 : : bool
2156 : 231589 : pass_omp_simd_clone::gate (function *)
2157 : : {
2158 : 231589 : return targetm.simd_clone.compute_vecsize_and_simdlen != NULL;
2159 : : }
2160 : :
2161 : : } // anon namespace
2162 : :
2163 : : simple_ipa_opt_pass *
2164 : 289302 : make_pass_omp_simd_clone (gcc::context *ctxt)
2165 : : {
2166 : 289302 : return new pass_omp_simd_clone (ctxt);
2167 : : }
|