Import GCC-8 to a new vendor branch
[dragonfly.git] / contrib / gcc-8.0 / gcc / omp-simd-clone.c
1 /* OMP constructs' SIMD clone supporting code.
2
3 Copyright (C) 2005-2018 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "cfghooks.h"
29 #include "alloc-pool.h"
30 #include "tree-pass.h"
31 #include "ssa.h"
32 #include "cgraph.h"
33 #include "pretty-print.h"
34 #include "diagnostic-core.h"
35 #include "fold-const.h"
36 #include "stor-layout.h"
37 #include "cfganal.h"
38 #include "gimplify.h"
39 #include "gimple-iterator.h"
40 #include "gimplify-me.h"
41 #include "gimple-walk.h"
42 #include "langhooks.h"
43 #include "tree-cfg.h"
44 #include "tree-into-ssa.h"
45 #include "tree-dfa.h"
46 #include "cfgloop.h"
47 #include "symbol-summary.h"
48 #include "ipa-param-manipulation.h"
49 #include "tree-eh.h"
50 #include "varasm.h"
51 #include "stringpool.h"
52 #include "attribs.h"
53 #include "omp-simd-clone.h"
54
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 }
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
459   DECL_BUILT_IN_CLASS (new_node->decl) = NOT_BUILT_IN;
460   DECL_FUNCTION_CODE (new_node->decl) = (enum built_in_function) 0;
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         }
776       if (simd_clone_subparts (TREE_TYPE (arg)) == node->simdclone->simdlen)
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         {
787           unsigned int simdlen = simd_clone_subparts (TREE_TYPE (arg));
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
933           && simd_clone_subparts (vectype) < node->simdclone->simdlen)
934         j += node->simdclone->simdlen / simd_clone_subparts (vectype) - 1;
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);
1138       incr_bb->count = profile_count::zero ();
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);
1149           incr_bb->count += e->count ();
1150         }
1151     }
1152   else if (node->simdclone->inbranch)
1153     {
1154       incr_bb = create_empty_bb (entry_bb);
1155       incr_bb->count = profile_count::zero ();
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 ();
1252       incr_bb->count += e->count ();
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),
1396                                call, entry_bb->count);
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
1574 void
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 }