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