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