xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/omp-simd-clone.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* OMP constructs' SIMD clone supporting code.
21debfc3dSmrg 
3*8feb0f0bSmrg Copyright (C) 2005-2020 Free Software Foundation, Inc.
41debfc3dSmrg 
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg 
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
81debfc3dSmrg the terms of the GNU General Public License as published by the Free
91debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
101debfc3dSmrg version.
111debfc3dSmrg 
121debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
131debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
141debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
151debfc3dSmrg for more details.
161debfc3dSmrg 
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3.  If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>.  */
201debfc3dSmrg 
211debfc3dSmrg #include "config.h"
221debfc3dSmrg #include "system.h"
231debfc3dSmrg #include "coretypes.h"
241debfc3dSmrg #include "backend.h"
251debfc3dSmrg #include "target.h"
261debfc3dSmrg #include "tree.h"
271debfc3dSmrg #include "gimple.h"
281debfc3dSmrg #include "cfghooks.h"
291debfc3dSmrg #include "alloc-pool.h"
301debfc3dSmrg #include "tree-pass.h"
311debfc3dSmrg #include "ssa.h"
321debfc3dSmrg #include "cgraph.h"
331debfc3dSmrg #include "pretty-print.h"
341debfc3dSmrg #include "diagnostic-core.h"
351debfc3dSmrg #include "fold-const.h"
361debfc3dSmrg #include "stor-layout.h"
371debfc3dSmrg #include "cfganal.h"
381debfc3dSmrg #include "gimplify.h"
391debfc3dSmrg #include "gimple-iterator.h"
401debfc3dSmrg #include "gimplify-me.h"
411debfc3dSmrg #include "gimple-walk.h"
421debfc3dSmrg #include "langhooks.h"
431debfc3dSmrg #include "tree-cfg.h"
441debfc3dSmrg #include "tree-into-ssa.h"
451debfc3dSmrg #include "tree-dfa.h"
461debfc3dSmrg #include "cfgloop.h"
471debfc3dSmrg #include "symbol-summary.h"
48a2dc1f3fSmrg #include "ipa-param-manipulation.h"
491debfc3dSmrg #include "tree-eh.h"
501debfc3dSmrg #include "varasm.h"
51a2dc1f3fSmrg #include "stringpool.h"
52a2dc1f3fSmrg #include "attribs.h"
53a2dc1f3fSmrg #include "omp-simd-clone.h"
541debfc3dSmrg 
55a2dc1f3fSmrg /* Return the number of elements in vector type VECTYPE, which is associated
56a2dc1f3fSmrg    with a SIMD clone.  At present these always have a constant length.  */
57a2dc1f3fSmrg 
58a2dc1f3fSmrg static unsigned HOST_WIDE_INT
simd_clone_subparts(tree vectype)59a2dc1f3fSmrg simd_clone_subparts (tree vectype)
60a2dc1f3fSmrg {
61a2dc1f3fSmrg   return TYPE_VECTOR_SUBPARTS (vectype).to_constant ();
62a2dc1f3fSmrg }
631debfc3dSmrg 
641debfc3dSmrg /* Allocate a fresh `simd_clone' and return it.  NARGS is the number
651debfc3dSmrg    of arguments to reserve space for.  */
661debfc3dSmrg 
671debfc3dSmrg static struct cgraph_simd_clone *
simd_clone_struct_alloc(int nargs)681debfc3dSmrg simd_clone_struct_alloc (int nargs)
691debfc3dSmrg {
701debfc3dSmrg   struct cgraph_simd_clone *clone_info;
711debfc3dSmrg   size_t len = (sizeof (struct cgraph_simd_clone)
721debfc3dSmrg 		+ nargs * sizeof (struct cgraph_simd_clone_arg));
731debfc3dSmrg   clone_info = (struct cgraph_simd_clone *)
741debfc3dSmrg 	       ggc_internal_cleared_alloc (len);
751debfc3dSmrg   return clone_info;
761debfc3dSmrg }
771debfc3dSmrg 
781debfc3dSmrg /* Make a copy of the `struct cgraph_simd_clone' in FROM to TO.  */
791debfc3dSmrg 
801debfc3dSmrg static inline void
simd_clone_struct_copy(struct cgraph_simd_clone * to,struct cgraph_simd_clone * from)811debfc3dSmrg simd_clone_struct_copy (struct cgraph_simd_clone *to,
821debfc3dSmrg 			struct cgraph_simd_clone *from)
831debfc3dSmrg {
841debfc3dSmrg   memcpy (to, from, (sizeof (struct cgraph_simd_clone)
851debfc3dSmrg 		     + ((from->nargs - from->inbranch)
861debfc3dSmrg 			* sizeof (struct cgraph_simd_clone_arg))));
871debfc3dSmrg }
881debfc3dSmrg 
89*8feb0f0bSmrg /* Fill an empty vector ARGS with parameter types of function FNDECL.  This
90*8feb0f0bSmrg    uses TYPE_ARG_TYPES if available, otherwise falls back to types of
911debfc3dSmrg    DECL_ARGUMENTS types.  */
921debfc3dSmrg 
93*8feb0f0bSmrg static void
simd_clone_vector_of_formal_parm_types(vec<tree> * args,tree fndecl)94*8feb0f0bSmrg simd_clone_vector_of_formal_parm_types (vec<tree> *args, tree fndecl)
951debfc3dSmrg {
961debfc3dSmrg   if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
97*8feb0f0bSmrg     {
98*8feb0f0bSmrg       push_function_arg_types (args, TREE_TYPE (fndecl));
99*8feb0f0bSmrg       return;
100*8feb0f0bSmrg     }
101*8feb0f0bSmrg   push_function_arg_decls (args, fndecl);
1021debfc3dSmrg   unsigned int i;
1031debfc3dSmrg   tree arg;
104*8feb0f0bSmrg   FOR_EACH_VEC_ELT (*args, i, arg)
105*8feb0f0bSmrg     (*args)[i] = TREE_TYPE ((*args)[i]);
1061debfc3dSmrg }
1071debfc3dSmrg 
1081debfc3dSmrg /* Given a simd function in NODE, extract the simd specific
1091debfc3dSmrg    information from the OMP clauses passed in CLAUSES, and return
1101debfc3dSmrg    the struct cgraph_simd_clone * if it should be cloned.  *INBRANCH_SPECIFIED
1111debfc3dSmrg    is set to TRUE if the `inbranch' or `notinbranch' clause specified,
1121debfc3dSmrg    otherwise set to FALSE.  */
1131debfc3dSmrg 
1141debfc3dSmrg static struct cgraph_simd_clone *
simd_clone_clauses_extract(struct cgraph_node * node,tree clauses,bool * inbranch_specified)1151debfc3dSmrg simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
1161debfc3dSmrg 			    bool *inbranch_specified)
1171debfc3dSmrg {
118*8feb0f0bSmrg   auto_vec<tree> args;
119*8feb0f0bSmrg   simd_clone_vector_of_formal_parm_types (&args, node->decl);
1201debfc3dSmrg   tree t;
1211debfc3dSmrg   int n;
1221debfc3dSmrg   *inbranch_specified = false;
1231debfc3dSmrg 
1241debfc3dSmrg   n = args.length ();
1251debfc3dSmrg   if (n > 0 && args.last () == void_type_node)
1261debfc3dSmrg     n--;
1271debfc3dSmrg 
1281debfc3dSmrg   /* Allocate one more than needed just in case this is an in-branch
1291debfc3dSmrg      clone which will require a mask argument.  */
1301debfc3dSmrg   struct cgraph_simd_clone *clone_info = simd_clone_struct_alloc (n + 1);
1311debfc3dSmrg   clone_info->nargs = n;
1321debfc3dSmrg 
1331debfc3dSmrg   if (!clauses)
1341debfc3dSmrg     goto out;
1351debfc3dSmrg 
1361debfc3dSmrg   clauses = TREE_VALUE (clauses);
1371debfc3dSmrg   if (!clauses || TREE_CODE (clauses) != OMP_CLAUSE)
1381debfc3dSmrg     goto out;
1391debfc3dSmrg 
1401debfc3dSmrg   for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t))
1411debfc3dSmrg     {
1421debfc3dSmrg       switch (OMP_CLAUSE_CODE (t))
1431debfc3dSmrg 	{
1441debfc3dSmrg 	case OMP_CLAUSE_INBRANCH:
1451debfc3dSmrg 	  clone_info->inbranch = 1;
1461debfc3dSmrg 	  *inbranch_specified = true;
1471debfc3dSmrg 	  break;
1481debfc3dSmrg 	case OMP_CLAUSE_NOTINBRANCH:
1491debfc3dSmrg 	  clone_info->inbranch = 0;
1501debfc3dSmrg 	  *inbranch_specified = true;
1511debfc3dSmrg 	  break;
1521debfc3dSmrg 	case OMP_CLAUSE_SIMDLEN:
1531debfc3dSmrg 	  clone_info->simdlen
1541debfc3dSmrg 	    = TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
1551debfc3dSmrg 	  break;
1561debfc3dSmrg 	case OMP_CLAUSE_LINEAR:
1571debfc3dSmrg 	  {
1581debfc3dSmrg 	    tree decl = OMP_CLAUSE_DECL (t);
1591debfc3dSmrg 	    tree step = OMP_CLAUSE_LINEAR_STEP (t);
1601debfc3dSmrg 	    int argno = TREE_INT_CST_LOW (decl);
1611debfc3dSmrg 	    if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (t))
1621debfc3dSmrg 	      {
1631debfc3dSmrg 		enum cgraph_simd_clone_arg_type arg_type;
1641debfc3dSmrg 		if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
1651debfc3dSmrg 		  switch (OMP_CLAUSE_LINEAR_KIND (t))
1661debfc3dSmrg 		    {
1671debfc3dSmrg 		    case OMP_CLAUSE_LINEAR_REF:
1681debfc3dSmrg 		      arg_type
1691debfc3dSmrg 			= SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP;
1701debfc3dSmrg 		      break;
1711debfc3dSmrg 		    case OMP_CLAUSE_LINEAR_UVAL:
1721debfc3dSmrg 		      arg_type
1731debfc3dSmrg 			= SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP;
1741debfc3dSmrg 		      break;
1751debfc3dSmrg 		    case OMP_CLAUSE_LINEAR_VAL:
1761debfc3dSmrg 		    case OMP_CLAUSE_LINEAR_DEFAULT:
1771debfc3dSmrg 		      arg_type
1781debfc3dSmrg 			= SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP;
1791debfc3dSmrg 		      break;
1801debfc3dSmrg 		    default:
1811debfc3dSmrg 		      gcc_unreachable ();
1821debfc3dSmrg 		    }
1831debfc3dSmrg 		else
1841debfc3dSmrg 		  arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP;
1851debfc3dSmrg 		clone_info->args[argno].arg_type = arg_type;
1861debfc3dSmrg 		clone_info->args[argno].linear_step = tree_to_shwi (step);
1871debfc3dSmrg 		gcc_assert (clone_info->args[argno].linear_step >= 0
1881debfc3dSmrg 			    && clone_info->args[argno].linear_step < n);
1891debfc3dSmrg 	      }
1901debfc3dSmrg 	    else
1911debfc3dSmrg 	      {
1921debfc3dSmrg 		if (POINTER_TYPE_P (args[argno]))
1931debfc3dSmrg 		  step = fold_convert (ssizetype, step);
1941debfc3dSmrg 		if (!tree_fits_shwi_p (step))
1951debfc3dSmrg 		  {
1961debfc3dSmrg 		    warning_at (OMP_CLAUSE_LOCATION (t), 0,
1971debfc3dSmrg 				"ignoring large linear step");
1981debfc3dSmrg 		    return NULL;
1991debfc3dSmrg 		  }
2001debfc3dSmrg 		else if (integer_zerop (step))
2011debfc3dSmrg 		  {
2021debfc3dSmrg 		    warning_at (OMP_CLAUSE_LOCATION (t), 0,
2031debfc3dSmrg 				"ignoring zero linear step");
2041debfc3dSmrg 		    return NULL;
2051debfc3dSmrg 		  }
2061debfc3dSmrg 		else
2071debfc3dSmrg 		  {
2081debfc3dSmrg 		    enum cgraph_simd_clone_arg_type arg_type;
2091debfc3dSmrg 		    if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
2101debfc3dSmrg 		      switch (OMP_CLAUSE_LINEAR_KIND (t))
2111debfc3dSmrg 			{
2121debfc3dSmrg 			case OMP_CLAUSE_LINEAR_REF:
2131debfc3dSmrg 			  arg_type
2141debfc3dSmrg 			    = SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP;
2151debfc3dSmrg 			  break;
2161debfc3dSmrg 			case OMP_CLAUSE_LINEAR_UVAL:
2171debfc3dSmrg 			  arg_type
2181debfc3dSmrg 			    = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP;
2191debfc3dSmrg 			  break;
2201debfc3dSmrg 			case OMP_CLAUSE_LINEAR_VAL:
2211debfc3dSmrg 			case OMP_CLAUSE_LINEAR_DEFAULT:
2221debfc3dSmrg 			  arg_type
2231debfc3dSmrg 			    = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP;
2241debfc3dSmrg 			  break;
2251debfc3dSmrg 			default:
2261debfc3dSmrg 			  gcc_unreachable ();
2271debfc3dSmrg 			}
2281debfc3dSmrg 		    else
2291debfc3dSmrg 		      arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP;
2301debfc3dSmrg 		    clone_info->args[argno].arg_type = arg_type;
2311debfc3dSmrg 		    clone_info->args[argno].linear_step = tree_to_shwi (step);
2321debfc3dSmrg 		  }
2331debfc3dSmrg 	      }
2341debfc3dSmrg 	    break;
2351debfc3dSmrg 	  }
2361debfc3dSmrg 	case OMP_CLAUSE_UNIFORM:
2371debfc3dSmrg 	  {
2381debfc3dSmrg 	    tree decl = OMP_CLAUSE_DECL (t);
2391debfc3dSmrg 	    int argno = tree_to_uhwi (decl);
2401debfc3dSmrg 	    clone_info->args[argno].arg_type
2411debfc3dSmrg 	      = SIMD_CLONE_ARG_TYPE_UNIFORM;
2421debfc3dSmrg 	    break;
2431debfc3dSmrg 	  }
2441debfc3dSmrg 	case OMP_CLAUSE_ALIGNED:
2451debfc3dSmrg 	  {
246a05ac97eSmrg 	    /* Ignore aligned (x) for declare simd, for the ABI we really
247a05ac97eSmrg 	       need an alignment specified.  */
248a05ac97eSmrg 	    if (OMP_CLAUSE_ALIGNED_ALIGNMENT (t) == NULL_TREE)
249a05ac97eSmrg 	      break;
2501debfc3dSmrg 	    tree decl = OMP_CLAUSE_DECL (t);
2511debfc3dSmrg 	    int argno = tree_to_uhwi (decl);
2521debfc3dSmrg 	    clone_info->args[argno].alignment
2531debfc3dSmrg 	      = TREE_INT_CST_LOW (OMP_CLAUSE_ALIGNED_ALIGNMENT (t));
2541debfc3dSmrg 	    break;
2551debfc3dSmrg 	  }
2561debfc3dSmrg 	default:
2571debfc3dSmrg 	  break;
2581debfc3dSmrg 	}
2591debfc3dSmrg     }
2601debfc3dSmrg 
2611debfc3dSmrg  out:
2621debfc3dSmrg   if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (node->decl))))
2631debfc3dSmrg     {
2641debfc3dSmrg       warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
2651debfc3dSmrg 		  "ignoring %<#pragma omp declare simd%> on function "
2661debfc3dSmrg 		  "with %<_Atomic%> qualified return type");
2671debfc3dSmrg       return NULL;
2681debfc3dSmrg     }
2691debfc3dSmrg 
2701debfc3dSmrg   for (unsigned int argno = 0; argno < clone_info->nargs; argno++)
2711debfc3dSmrg     if (TYPE_ATOMIC (args[argno])
2721debfc3dSmrg 	&& clone_info->args[argno].arg_type != SIMD_CLONE_ARG_TYPE_UNIFORM)
2731debfc3dSmrg       {
2741debfc3dSmrg 	warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
2751debfc3dSmrg 		    "ignoring %<#pragma omp declare simd%> on function "
2761debfc3dSmrg 		    "with %<_Atomic%> qualified non-%<uniform%> argument");
2771debfc3dSmrg 	args.release ();
2781debfc3dSmrg 	return NULL;
2791debfc3dSmrg       }
2801debfc3dSmrg 
2811debfc3dSmrg   return clone_info;
2821debfc3dSmrg }
2831debfc3dSmrg 
2841debfc3dSmrg /* Given a SIMD clone in NODE, calculate the characteristic data
2851debfc3dSmrg    type and return the coresponding type.  The characteristic data
2861debfc3dSmrg    type is computed as described in the Intel Vector ABI.  */
2871debfc3dSmrg 
2881debfc3dSmrg static tree
simd_clone_compute_base_data_type(struct cgraph_node * node,struct cgraph_simd_clone * clone_info)2891debfc3dSmrg simd_clone_compute_base_data_type (struct cgraph_node *node,
2901debfc3dSmrg 				   struct cgraph_simd_clone *clone_info)
2911debfc3dSmrg {
2921debfc3dSmrg   tree type = integer_type_node;
2931debfc3dSmrg   tree fndecl = node->decl;
2941debfc3dSmrg 
2951debfc3dSmrg   /* a) For non-void function, the characteristic data type is the
2961debfc3dSmrg         return type.  */
2971debfc3dSmrg   if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE)
2981debfc3dSmrg     type = TREE_TYPE (TREE_TYPE (fndecl));
2991debfc3dSmrg 
3001debfc3dSmrg   /* b) If the function has any non-uniform, non-linear parameters,
3011debfc3dSmrg         then the characteristic data type is the type of the first
3021debfc3dSmrg         such parameter.  */
3031debfc3dSmrg   else
3041debfc3dSmrg     {
305*8feb0f0bSmrg       auto_vec<tree> map;
306*8feb0f0bSmrg       simd_clone_vector_of_formal_parm_types (&map, fndecl);
3071debfc3dSmrg       for (unsigned int i = 0; i < clone_info->nargs; ++i)
3081debfc3dSmrg 	if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
3091debfc3dSmrg 	  {
3101debfc3dSmrg 	    type = map[i];
3111debfc3dSmrg 	    break;
3121debfc3dSmrg 	  }
3131debfc3dSmrg     }
3141debfc3dSmrg 
3151debfc3dSmrg   /* c) If the characteristic data type determined by a) or b) above
3161debfc3dSmrg         is struct, union, or class type which is pass-by-value (except
3171debfc3dSmrg         for the type that maps to the built-in complex data type), the
3181debfc3dSmrg         characteristic data type is int.  */
3191debfc3dSmrg   if (RECORD_OR_UNION_TYPE_P (type)
3201debfc3dSmrg       && !aggregate_value_p (type, NULL)
3211debfc3dSmrg       && TREE_CODE (type) != COMPLEX_TYPE)
3221debfc3dSmrg     return integer_type_node;
3231debfc3dSmrg 
3241debfc3dSmrg   /* d) If none of the above three classes is applicable, the
3251debfc3dSmrg         characteristic data type is int.  */
3261debfc3dSmrg 
3271debfc3dSmrg   return type;
3281debfc3dSmrg 
3291debfc3dSmrg   /* e) For Intel Xeon Phi native and offload compilation, if the
3301debfc3dSmrg         resulting characteristic data type is 8-bit or 16-bit integer
3311debfc3dSmrg         data type, the characteristic data type is int.  */
3321debfc3dSmrg   /* Well, we don't handle Xeon Phi yet.  */
3331debfc3dSmrg }
3341debfc3dSmrg 
3351debfc3dSmrg static tree
simd_clone_mangle(struct cgraph_node * node,struct cgraph_simd_clone * clone_info)3361debfc3dSmrg simd_clone_mangle (struct cgraph_node *node,
3371debfc3dSmrg 		   struct cgraph_simd_clone *clone_info)
3381debfc3dSmrg {
3391debfc3dSmrg   char vecsize_mangle = clone_info->vecsize_mangle;
3401debfc3dSmrg   char mask = clone_info->inbranch ? 'M' : 'N';
3411debfc3dSmrg   unsigned int simdlen = clone_info->simdlen;
3421debfc3dSmrg   unsigned int n;
3431debfc3dSmrg   pretty_printer pp;
3441debfc3dSmrg 
3451debfc3dSmrg   gcc_assert (vecsize_mangle && simdlen);
3461debfc3dSmrg 
3471debfc3dSmrg   pp_string (&pp, "_ZGV");
3481debfc3dSmrg   pp_character (&pp, vecsize_mangle);
3491debfc3dSmrg   pp_character (&pp, mask);
3501debfc3dSmrg   pp_decimal_int (&pp, simdlen);
3511debfc3dSmrg 
3521debfc3dSmrg   for (n = 0; n < clone_info->nargs; ++n)
3531debfc3dSmrg     {
3541debfc3dSmrg       struct cgraph_simd_clone_arg arg = clone_info->args[n];
3551debfc3dSmrg 
3561debfc3dSmrg       switch (arg.arg_type)
3571debfc3dSmrg 	{
3581debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_UNIFORM:
3591debfc3dSmrg 	  pp_character (&pp, 'u');
3601debfc3dSmrg 	  break;
3611debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
3621debfc3dSmrg 	  pp_character (&pp, 'l');
3631debfc3dSmrg 	  goto mangle_linear;
3641debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
3651debfc3dSmrg 	  pp_character (&pp, 'R');
3661debfc3dSmrg 	  goto mangle_linear;
3671debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
3681debfc3dSmrg 	  pp_character (&pp, 'L');
3691debfc3dSmrg 	  goto mangle_linear;
3701debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
3711debfc3dSmrg 	  pp_character (&pp, 'U');
3721debfc3dSmrg 	  goto mangle_linear;
3731debfc3dSmrg 	mangle_linear:
3741debfc3dSmrg 	  gcc_assert (arg.linear_step != 0);
3751debfc3dSmrg 	  if (arg.linear_step > 1)
3761debfc3dSmrg 	    pp_unsigned_wide_integer (&pp, arg.linear_step);
3771debfc3dSmrg 	  else if (arg.linear_step < 0)
3781debfc3dSmrg 	    {
3791debfc3dSmrg 	      pp_character (&pp, 'n');
3801debfc3dSmrg 	      pp_unsigned_wide_integer (&pp, (-(unsigned HOST_WIDE_INT)
3811debfc3dSmrg 					      arg.linear_step));
3821debfc3dSmrg 	    }
3831debfc3dSmrg 	  break;
3841debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
3851debfc3dSmrg 	  pp_string (&pp, "ls");
3861debfc3dSmrg 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
3871debfc3dSmrg 	  break;
3881debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
3891debfc3dSmrg 	  pp_string (&pp, "Rs");
3901debfc3dSmrg 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
3911debfc3dSmrg 	  break;
3921debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
3931debfc3dSmrg 	  pp_string (&pp, "Ls");
3941debfc3dSmrg 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
3951debfc3dSmrg 	  break;
3961debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
3971debfc3dSmrg 	  pp_string (&pp, "Us");
3981debfc3dSmrg 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
3991debfc3dSmrg 	  break;
4001debfc3dSmrg 	default:
4011debfc3dSmrg 	  pp_character (&pp, 'v');
4021debfc3dSmrg 	}
4031debfc3dSmrg       if (arg.alignment)
4041debfc3dSmrg 	{
4051debfc3dSmrg 	  pp_character (&pp, 'a');
4061debfc3dSmrg 	  pp_decimal_int (&pp, arg.alignment);
4071debfc3dSmrg 	}
4081debfc3dSmrg     }
4091debfc3dSmrg 
4101debfc3dSmrg   pp_underscore (&pp);
4111debfc3dSmrg   const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
4121debfc3dSmrg   if (*str == '*')
4131debfc3dSmrg     ++str;
4141debfc3dSmrg   pp_string (&pp, str);
4151debfc3dSmrg   str = pp_formatted_text (&pp);
4161debfc3dSmrg 
4171debfc3dSmrg   /* If there already is a SIMD clone with the same mangled name, don't
4181debfc3dSmrg      add another one.  This can happen e.g. for
4191debfc3dSmrg      #pragma omp declare simd
4201debfc3dSmrg      #pragma omp declare simd simdlen(8)
4211debfc3dSmrg      int foo (int, int);
4221debfc3dSmrg      if the simdlen is assumed to be 8 for the first one, etc.  */
4231debfc3dSmrg   for (struct cgraph_node *clone = node->simd_clones; clone;
4241debfc3dSmrg        clone = clone->simdclone->next_clone)
425a2dc1f3fSmrg     if (id_equal (DECL_ASSEMBLER_NAME (clone->decl), str))
4261debfc3dSmrg       return NULL_TREE;
4271debfc3dSmrg 
4281debfc3dSmrg   return get_identifier (str);
4291debfc3dSmrg }
4301debfc3dSmrg 
4311debfc3dSmrg /* Create a simd clone of OLD_NODE and return it.  */
4321debfc3dSmrg 
4331debfc3dSmrg static struct cgraph_node *
simd_clone_create(struct cgraph_node * old_node)4341debfc3dSmrg simd_clone_create (struct cgraph_node *old_node)
4351debfc3dSmrg {
4361debfc3dSmrg   struct cgraph_node *new_node;
4371debfc3dSmrg   if (old_node->definition)
4381debfc3dSmrg     {
4391debfc3dSmrg       if (!old_node->has_gimple_body_p ())
4401debfc3dSmrg 	return NULL;
4411debfc3dSmrg       old_node->get_body ();
4421debfc3dSmrg       new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL,
443*8feb0f0bSmrg 							   NULL, NULL,
4441debfc3dSmrg 							   "simdclone");
4451debfc3dSmrg     }
4461debfc3dSmrg   else
4471debfc3dSmrg     {
4481debfc3dSmrg       tree old_decl = old_node->decl;
4491debfc3dSmrg       tree new_decl = copy_node (old_node->decl);
450c0a68be4Smrg       DECL_NAME (new_decl) = clone_function_name_numbered (old_decl,
451c0a68be4Smrg 							   "simdclone");
4521debfc3dSmrg       SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
4531debfc3dSmrg       SET_DECL_RTL (new_decl, NULL);
4541debfc3dSmrg       DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
4551debfc3dSmrg       DECL_STATIC_DESTRUCTOR (new_decl) = 0;
4561debfc3dSmrg       new_node = old_node->create_version_clone (new_decl, vNULL, NULL);
4571debfc3dSmrg       if (old_node->in_other_partition)
4581debfc3dSmrg 	new_node->in_other_partition = 1;
4591debfc3dSmrg     }
4601debfc3dSmrg   if (new_node == NULL)
4611debfc3dSmrg     return new_node;
4621debfc3dSmrg 
463*8feb0f0bSmrg   set_decl_built_in_function (new_node->decl, NOT_BUILT_IN, 0);
4641debfc3dSmrg   TREE_PUBLIC (new_node->decl) = TREE_PUBLIC (old_node->decl);
4651debfc3dSmrg   DECL_COMDAT (new_node->decl) = DECL_COMDAT (old_node->decl);
4661debfc3dSmrg   DECL_WEAK (new_node->decl) = DECL_WEAK (old_node->decl);
4671debfc3dSmrg   DECL_EXTERNAL (new_node->decl) = DECL_EXTERNAL (old_node->decl);
4681debfc3dSmrg   DECL_VISIBILITY_SPECIFIED (new_node->decl)
4691debfc3dSmrg     = DECL_VISIBILITY_SPECIFIED (old_node->decl);
4701debfc3dSmrg   DECL_VISIBILITY (new_node->decl) = DECL_VISIBILITY (old_node->decl);
4711debfc3dSmrg   DECL_DLLIMPORT_P (new_node->decl) = DECL_DLLIMPORT_P (old_node->decl);
4721debfc3dSmrg   if (DECL_ONE_ONLY (old_node->decl))
4731debfc3dSmrg     make_decl_one_only (new_node->decl, DECL_ASSEMBLER_NAME (new_node->decl));
4741debfc3dSmrg 
4751debfc3dSmrg   /* The method cgraph_version_clone_with_body () will force the new
4761debfc3dSmrg      symbol local.  Undo this, and inherit external visibility from
4771debfc3dSmrg      the old node.  */
478*8feb0f0bSmrg   new_node->local = old_node->local;
4791debfc3dSmrg   new_node->externally_visible = old_node->externally_visible;
4801debfc3dSmrg 
4811debfc3dSmrg   return new_node;
4821debfc3dSmrg }
4831debfc3dSmrg 
4841debfc3dSmrg /* Adjust the return type of the given function to its appropriate
4851debfc3dSmrg    vector counterpart.  Returns a simd array to be used throughout the
4861debfc3dSmrg    function as a return value.  */
4871debfc3dSmrg 
4881debfc3dSmrg static tree
simd_clone_adjust_return_type(struct cgraph_node * node)4891debfc3dSmrg simd_clone_adjust_return_type (struct cgraph_node *node)
4901debfc3dSmrg {
4911debfc3dSmrg   tree fndecl = node->decl;
4921debfc3dSmrg   tree orig_rettype = TREE_TYPE (TREE_TYPE (fndecl));
4931debfc3dSmrg   unsigned int veclen;
4941debfc3dSmrg   tree t;
4951debfc3dSmrg 
4961debfc3dSmrg   /* Adjust the function return type.  */
4971debfc3dSmrg   if (orig_rettype == void_type_node)
4981debfc3dSmrg     return NULL_TREE;
4991debfc3dSmrg   t = TREE_TYPE (TREE_TYPE (fndecl));
5001debfc3dSmrg   if (INTEGRAL_TYPE_P (t) || POINTER_TYPE_P (t))
5011debfc3dSmrg     veclen = node->simdclone->vecsize_int;
5021debfc3dSmrg   else
5031debfc3dSmrg     veclen = node->simdclone->vecsize_float;
504a2dc1f3fSmrg   veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (t));
5051debfc3dSmrg   if (veclen > node->simdclone->simdlen)
5061debfc3dSmrg     veclen = node->simdclone->simdlen;
5071debfc3dSmrg   if (POINTER_TYPE_P (t))
5081debfc3dSmrg     t = pointer_sized_int_node;
5091debfc3dSmrg   if (veclen == node->simdclone->simdlen)
5101debfc3dSmrg     t = build_vector_type (t, node->simdclone->simdlen);
5111debfc3dSmrg   else
5121debfc3dSmrg     {
5131debfc3dSmrg       t = build_vector_type (t, veclen);
5141debfc3dSmrg       t = build_array_type_nelts (t, node->simdclone->simdlen / veclen);
5151debfc3dSmrg     }
5161debfc3dSmrg   TREE_TYPE (TREE_TYPE (fndecl)) = t;
5171debfc3dSmrg   if (!node->definition)
5181debfc3dSmrg     return NULL_TREE;
5191debfc3dSmrg 
5201debfc3dSmrg   t = DECL_RESULT (fndecl);
5211debfc3dSmrg   /* Adjust the DECL_RESULT.  */
5221debfc3dSmrg   gcc_assert (TREE_TYPE (t) != void_type_node);
5231debfc3dSmrg   TREE_TYPE (t) = TREE_TYPE (TREE_TYPE (fndecl));
5241debfc3dSmrg   relayout_decl (t);
5251debfc3dSmrg 
5261debfc3dSmrg   tree atype = build_array_type_nelts (orig_rettype,
5271debfc3dSmrg 				       node->simdclone->simdlen);
5281debfc3dSmrg   if (veclen != node->simdclone->simdlen)
5291debfc3dSmrg     return build1 (VIEW_CONVERT_EXPR, atype, t);
5301debfc3dSmrg 
5311debfc3dSmrg   /* Set up a SIMD array to use as the return value.  */
5321debfc3dSmrg   tree retval = create_tmp_var_raw (atype, "retval");
5331debfc3dSmrg   gimple_add_tmp_var (retval);
5341debfc3dSmrg   return retval;
5351debfc3dSmrg }
5361debfc3dSmrg 
5371debfc3dSmrg /* Each vector argument has a corresponding array to be used locally
5381debfc3dSmrg    as part of the eventual loop.  Create such temporary array and
5391debfc3dSmrg    return it.
5401debfc3dSmrg 
5411debfc3dSmrg    PREFIX is the prefix to be used for the temporary.
5421debfc3dSmrg 
5431debfc3dSmrg    TYPE is the inner element type.
5441debfc3dSmrg 
5451debfc3dSmrg    SIMDLEN is the number of elements.  */
5461debfc3dSmrg 
5471debfc3dSmrg static tree
create_tmp_simd_array(const char * prefix,tree type,int simdlen)5481debfc3dSmrg create_tmp_simd_array (const char *prefix, tree type, int simdlen)
5491debfc3dSmrg {
5501debfc3dSmrg   tree atype = build_array_type_nelts (type, simdlen);
5511debfc3dSmrg   tree avar = create_tmp_var_raw (atype, prefix);
5521debfc3dSmrg   gimple_add_tmp_var (avar);
5531debfc3dSmrg   return avar;
5541debfc3dSmrg }
5551debfc3dSmrg 
5561debfc3dSmrg /* Modify the function argument types to their corresponding vector
5571debfc3dSmrg    counterparts if appropriate.  Also, create one array for each simd
5581debfc3dSmrg    argument to be used locally when using the function arguments as
5591debfc3dSmrg    part of the loop.
5601debfc3dSmrg 
5611debfc3dSmrg    NODE is the function whose arguments are to be adjusted.
5621debfc3dSmrg 
563*8feb0f0bSmrg    If NODE does not represent function definition, returns NULL.  Otherwise
564*8feb0f0bSmrg    returns an adjustment class that will be filled describing how the argument
565*8feb0f0bSmrg    declarations will be remapped.  New arguments which are not to be remapped
566*8feb0f0bSmrg    are marked with USER_FLAG.  */
5671debfc3dSmrg 
568*8feb0f0bSmrg static ipa_param_body_adjustments *
simd_clone_adjust_argument_types(struct cgraph_node * node)5691debfc3dSmrg simd_clone_adjust_argument_types (struct cgraph_node *node)
5701debfc3dSmrg {
571*8feb0f0bSmrg   auto_vec<tree> args;
5721debfc3dSmrg 
5731debfc3dSmrg   if (node->definition)
574*8feb0f0bSmrg     push_function_arg_decls (&args, node->decl);
5751debfc3dSmrg   else
576*8feb0f0bSmrg     simd_clone_vector_of_formal_parm_types (&args, node->decl);
5771debfc3dSmrg   struct cgraph_simd_clone *sc = node->simdclone;
578*8feb0f0bSmrg   vec<ipa_adjusted_param, va_gc> *new_params = NULL;
579*8feb0f0bSmrg   vec_safe_reserve (new_params, sc->nargs);
580*8feb0f0bSmrg   unsigned i, j, veclen;
5811debfc3dSmrg 
5821debfc3dSmrg   for (i = 0; i < sc->nargs; ++i)
5831debfc3dSmrg     {
584*8feb0f0bSmrg       ipa_adjusted_param adj;
5851debfc3dSmrg       memset (&adj, 0, sizeof (adj));
5861debfc3dSmrg       tree parm = args[i];
5871debfc3dSmrg       tree parm_type = node->definition ? TREE_TYPE (parm) : parm;
5881debfc3dSmrg       adj.base_index = i;
589*8feb0f0bSmrg       adj.prev_clone_index = i;
5901debfc3dSmrg 
5911debfc3dSmrg       sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
5921debfc3dSmrg       sc->args[i].orig_type = parm_type;
5931debfc3dSmrg 
5941debfc3dSmrg       switch (sc->args[i].arg_type)
5951debfc3dSmrg 	{
5961debfc3dSmrg 	default:
5971debfc3dSmrg 	  /* No adjustment necessary for scalar arguments.  */
598*8feb0f0bSmrg 	  adj.op = IPA_PARAM_OP_COPY;
5991debfc3dSmrg 	  break;
6001debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
6011debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
6021debfc3dSmrg 	  if (node->definition)
6031debfc3dSmrg 	    sc->args[i].simd_array
6041debfc3dSmrg 	      = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
6051debfc3dSmrg 				       TREE_TYPE (parm_type),
6061debfc3dSmrg 				       sc->simdlen);
607*8feb0f0bSmrg 	  adj.op = IPA_PARAM_OP_COPY;
6081debfc3dSmrg 	  break;
6091debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
6101debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
6111debfc3dSmrg 	case SIMD_CLONE_ARG_TYPE_VECTOR:
6121debfc3dSmrg 	  if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type))
6131debfc3dSmrg 	    veclen = sc->vecsize_int;
6141debfc3dSmrg 	  else
6151debfc3dSmrg 	    veclen = sc->vecsize_float;
616a2dc1f3fSmrg 	  veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type));
6171debfc3dSmrg 	  if (veclen > sc->simdlen)
6181debfc3dSmrg 	    veclen = sc->simdlen;
619*8feb0f0bSmrg 	  adj.op = IPA_PARAM_OP_NEW;
620*8feb0f0bSmrg 	  adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
6211debfc3dSmrg 	  if (POINTER_TYPE_P (parm_type))
6221debfc3dSmrg 	    adj.type = build_vector_type (pointer_sized_int_node, veclen);
6231debfc3dSmrg 	  else
6241debfc3dSmrg 	    adj.type = build_vector_type (parm_type, veclen);
6251debfc3dSmrg 	  sc->args[i].vector_type = adj.type;
6261debfc3dSmrg 	  for (j = veclen; j < sc->simdlen; j += veclen)
6271debfc3dSmrg 	    {
628*8feb0f0bSmrg 	      vec_safe_push (new_params, adj);
6291debfc3dSmrg 	      if (j == veclen)
6301debfc3dSmrg 		{
6311debfc3dSmrg 		  memset (&adj, 0, sizeof (adj));
632*8feb0f0bSmrg 		  adj.op = IPA_PARAM_OP_NEW;
633*8feb0f0bSmrg 		  adj.user_flag = 1;
634*8feb0f0bSmrg 		  adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
6351debfc3dSmrg 		  adj.base_index = i;
636*8feb0f0bSmrg 		  adj.prev_clone_index = i;
6371debfc3dSmrg 		  adj.type = sc->args[i].vector_type;
6381debfc3dSmrg 		}
6391debfc3dSmrg 	    }
6401debfc3dSmrg 
6411debfc3dSmrg 	  if (node->definition)
6421debfc3dSmrg 	    sc->args[i].simd_array
6431debfc3dSmrg 	      = create_tmp_simd_array (DECL_NAME (parm)
6441debfc3dSmrg 				       ? IDENTIFIER_POINTER (DECL_NAME (parm))
6451debfc3dSmrg 				       : NULL, parm_type, sc->simdlen);
6461debfc3dSmrg 	}
647*8feb0f0bSmrg       vec_safe_push (new_params, adj);
6481debfc3dSmrg     }
6491debfc3dSmrg 
6501debfc3dSmrg   if (sc->inbranch)
6511debfc3dSmrg     {
6521debfc3dSmrg       tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
653*8feb0f0bSmrg       ipa_adjusted_param adj;
6541debfc3dSmrg       memset (&adj, 0, sizeof (adj));
655*8feb0f0bSmrg       adj.op = IPA_PARAM_OP_NEW;
656*8feb0f0bSmrg       adj.user_flag = 1;
657*8feb0f0bSmrg       adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
6581debfc3dSmrg 
6591debfc3dSmrg       adj.base_index = i;
660*8feb0f0bSmrg       adj.prev_clone_index = i;
6611debfc3dSmrg       if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
6621debfc3dSmrg 	veclen = sc->vecsize_int;
6631debfc3dSmrg       else
6641debfc3dSmrg 	veclen = sc->vecsize_float;
665a2dc1f3fSmrg       veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type));
6661debfc3dSmrg       if (veclen > sc->simdlen)
6671debfc3dSmrg 	veclen = sc->simdlen;
6681debfc3dSmrg       if (sc->mask_mode != VOIDmode)
6691debfc3dSmrg 	adj.type
6701debfc3dSmrg 	  = lang_hooks.types.type_for_mode (sc->mask_mode, 1);
6711debfc3dSmrg       else if (POINTER_TYPE_P (base_type))
6721debfc3dSmrg 	adj.type = build_vector_type (pointer_sized_int_node, veclen);
6731debfc3dSmrg       else
6741debfc3dSmrg 	adj.type = build_vector_type (base_type, veclen);
675*8feb0f0bSmrg       vec_safe_push (new_params, adj);
6761debfc3dSmrg 
6771debfc3dSmrg       for (j = veclen; j < sc->simdlen; j += veclen)
678*8feb0f0bSmrg 	vec_safe_push (new_params, adj);
6791debfc3dSmrg 
6801debfc3dSmrg       /* We have previously allocated one extra entry for the mask.  Use
6811debfc3dSmrg 	 it and fill it.  */
6821debfc3dSmrg       sc->nargs++;
6831debfc3dSmrg       if (sc->mask_mode != VOIDmode)
6841debfc3dSmrg 	base_type = boolean_type_node;
6851debfc3dSmrg       if (node->definition)
6861debfc3dSmrg 	{
6871debfc3dSmrg 	  sc->args[i].orig_arg
6881debfc3dSmrg 	    = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type);
6891debfc3dSmrg 	  if (sc->mask_mode == VOIDmode)
6901debfc3dSmrg 	    sc->args[i].simd_array
6911debfc3dSmrg 	      = create_tmp_simd_array ("mask", base_type, sc->simdlen);
6921debfc3dSmrg 	  else if (veclen < sc->simdlen)
6931debfc3dSmrg 	    sc->args[i].simd_array
6941debfc3dSmrg 	      = create_tmp_simd_array ("mask", adj.type, sc->simdlen / veclen);
6951debfc3dSmrg 	  else
6961debfc3dSmrg 	    sc->args[i].simd_array = NULL_TREE;
6971debfc3dSmrg 	}
6981debfc3dSmrg       sc->args[i].orig_type = base_type;
6991debfc3dSmrg       sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK;
7001debfc3dSmrg     }
7011debfc3dSmrg 
7021debfc3dSmrg   if (node->definition)
703*8feb0f0bSmrg     {
704*8feb0f0bSmrg       ipa_param_body_adjustments *adjustments
705*8feb0f0bSmrg 	= new ipa_param_body_adjustments (new_params, node->decl);
706*8feb0f0bSmrg 
707*8feb0f0bSmrg       adjustments->modify_formal_parameters ();
708*8feb0f0bSmrg       return adjustments;
709*8feb0f0bSmrg     }
7101debfc3dSmrg   else
7111debfc3dSmrg     {
7121debfc3dSmrg       tree new_arg_types = NULL_TREE, new_reversed;
7131debfc3dSmrg       bool last_parm_void = false;
7141debfc3dSmrg       if (args.length () > 0 && args.last () == void_type_node)
7151debfc3dSmrg 	last_parm_void = true;
7161debfc3dSmrg 
7171debfc3dSmrg       gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
718*8feb0f0bSmrg       j = vec_safe_length (new_params);
7191debfc3dSmrg       for (i = 0; i < j; i++)
7201debfc3dSmrg 	{
721*8feb0f0bSmrg 	  struct ipa_adjusted_param *adj = &(*new_params)[i];
7221debfc3dSmrg 	  tree ptype;
723*8feb0f0bSmrg 	  if (adj->op == IPA_PARAM_OP_COPY)
7241debfc3dSmrg 	    ptype = args[adj->base_index];
7251debfc3dSmrg 	  else
7261debfc3dSmrg 	    ptype = adj->type;
7271debfc3dSmrg 	  new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types);
7281debfc3dSmrg 	}
7291debfc3dSmrg       new_reversed = nreverse (new_arg_types);
7301debfc3dSmrg       if (last_parm_void)
7311debfc3dSmrg 	{
7321debfc3dSmrg 	  if (new_reversed)
7331debfc3dSmrg 	    TREE_CHAIN (new_arg_types) = void_list_node;
7341debfc3dSmrg 	  else
7351debfc3dSmrg 	    new_reversed = void_list_node;
7361debfc3dSmrg 	}
737c0a68be4Smrg       TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed;
738*8feb0f0bSmrg       return NULL;
7391debfc3dSmrg     }
7401debfc3dSmrg }
7411debfc3dSmrg 
7421debfc3dSmrg /* Initialize and copy the function arguments in NODE to their
7431debfc3dSmrg    corresponding local simd arrays.  Returns a fresh gimple_seq with
7441debfc3dSmrg    the instruction sequence generated.  */
7451debfc3dSmrg 
7461debfc3dSmrg static gimple_seq
simd_clone_init_simd_arrays(struct cgraph_node * node,ipa_param_body_adjustments * adjustments)7471debfc3dSmrg simd_clone_init_simd_arrays (struct cgraph_node *node,
748*8feb0f0bSmrg 			     ipa_param_body_adjustments *adjustments)
7491debfc3dSmrg {
7501debfc3dSmrg   gimple_seq seq = NULL;
7511debfc3dSmrg   unsigned i = 0, j = 0, k;
7521debfc3dSmrg 
7531debfc3dSmrg   for (tree arg = DECL_ARGUMENTS (node->decl);
7541debfc3dSmrg        arg;
7551debfc3dSmrg        arg = DECL_CHAIN (arg), i++, j++)
7561debfc3dSmrg     {
757*8feb0f0bSmrg       if ((*adjustments->m_adj_params)[j].op == IPA_PARAM_OP_COPY
7581debfc3dSmrg 	  || POINTER_TYPE_P (TREE_TYPE (arg)))
7591debfc3dSmrg 	continue;
7601debfc3dSmrg 
7611debfc3dSmrg       node->simdclone->args[i].vector_arg = arg;
7621debfc3dSmrg 
7631debfc3dSmrg       tree array = node->simdclone->args[i].simd_array;
7641debfc3dSmrg       if (node->simdclone->mask_mode != VOIDmode
7651debfc3dSmrg 	  && node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
7661debfc3dSmrg 	{
7671debfc3dSmrg 	  if (array == NULL_TREE)
7681debfc3dSmrg 	    continue;
7691debfc3dSmrg 	  unsigned int l
7701debfc3dSmrg 	    = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array))));
7711debfc3dSmrg 	  for (k = 0; k <= l; k++)
7721debfc3dSmrg 	    {
7731debfc3dSmrg 	      if (k)
7741debfc3dSmrg 		{
7751debfc3dSmrg 		  arg = DECL_CHAIN (arg);
7761debfc3dSmrg 		  j++;
7771debfc3dSmrg 		}
7781debfc3dSmrg 	      tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
7791debfc3dSmrg 			       array, size_int (k), NULL, NULL);
7801debfc3dSmrg 	      t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
7811debfc3dSmrg 	      gimplify_and_add (t, &seq);
7821debfc3dSmrg 	    }
7831debfc3dSmrg 	  continue;
7841debfc3dSmrg 	}
785a2dc1f3fSmrg       if (simd_clone_subparts (TREE_TYPE (arg)) == node->simdclone->simdlen)
7861debfc3dSmrg 	{
7871debfc3dSmrg 	  tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
7881debfc3dSmrg 	  tree ptr = build_fold_addr_expr (array);
7891debfc3dSmrg 	  tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
7901debfc3dSmrg 			   build_int_cst (ptype, 0));
7911debfc3dSmrg 	  t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
7921debfc3dSmrg 	  gimplify_and_add (t, &seq);
7931debfc3dSmrg 	}
7941debfc3dSmrg       else
7951debfc3dSmrg 	{
796a2dc1f3fSmrg 	  unsigned int simdlen = simd_clone_subparts (TREE_TYPE (arg));
7971debfc3dSmrg 	  tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
7981debfc3dSmrg 	  for (k = 0; k < node->simdclone->simdlen; k += simdlen)
7991debfc3dSmrg 	    {
8001debfc3dSmrg 	      tree ptr = build_fold_addr_expr (array);
8011debfc3dSmrg 	      int elemsize;
8021debfc3dSmrg 	      if (k)
8031debfc3dSmrg 		{
8041debfc3dSmrg 		  arg = DECL_CHAIN (arg);
8051debfc3dSmrg 		  j++;
8061debfc3dSmrg 		}
807a2dc1f3fSmrg 	      tree elemtype = TREE_TYPE (TREE_TYPE (arg));
808a2dc1f3fSmrg 	      elemsize = GET_MODE_SIZE (SCALAR_TYPE_MODE (elemtype));
8091debfc3dSmrg 	      tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
8101debfc3dSmrg 			       build_int_cst (ptype, k * elemsize));
8111debfc3dSmrg 	      t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
8121debfc3dSmrg 	      gimplify_and_add (t, &seq);
8131debfc3dSmrg 	    }
8141debfc3dSmrg 	}
8151debfc3dSmrg     }
8161debfc3dSmrg   return seq;
8171debfc3dSmrg }
8181debfc3dSmrg 
8191debfc3dSmrg /* Callback info for ipa_simd_modify_stmt_ops below.  */
8201debfc3dSmrg 
8211debfc3dSmrg struct modify_stmt_info {
822*8feb0f0bSmrg   ipa_param_body_adjustments *adjustments;
8231debfc3dSmrg   gimple *stmt;
824*8feb0f0bSmrg   gimple *after_stmt;
8251debfc3dSmrg   /* True if the parent statement was modified by
8261debfc3dSmrg      ipa_simd_modify_stmt_ops.  */
8271debfc3dSmrg   bool modified;
8281debfc3dSmrg };
8291debfc3dSmrg 
8301debfc3dSmrg /* Callback for walk_gimple_op.
8311debfc3dSmrg 
8321debfc3dSmrg    Adjust operands from a given statement as specified in the
8331debfc3dSmrg    adjustments vector in the callback data.  */
8341debfc3dSmrg 
8351debfc3dSmrg static tree
ipa_simd_modify_stmt_ops(tree * tp,int * walk_subtrees,void * data)8361debfc3dSmrg ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
8371debfc3dSmrg {
8381debfc3dSmrg   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
8391debfc3dSmrg   struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
8401debfc3dSmrg   tree *orig_tp = tp;
8411debfc3dSmrg   if (TREE_CODE (*tp) == ADDR_EXPR)
8421debfc3dSmrg     tp = &TREE_OPERAND (*tp, 0);
843*8feb0f0bSmrg 
844*8feb0f0bSmrg   if (TREE_CODE (*tp) == BIT_FIELD_REF
845*8feb0f0bSmrg       || TREE_CODE (*tp) == IMAGPART_EXPR
846*8feb0f0bSmrg       || TREE_CODE (*tp) == REALPART_EXPR)
847*8feb0f0bSmrg     tp = &TREE_OPERAND (*tp, 0);
848*8feb0f0bSmrg 
849*8feb0f0bSmrg   tree repl = NULL_TREE;
850*8feb0f0bSmrg   ipa_param_body_replacement *pbr = NULL;
851*8feb0f0bSmrg 
8521debfc3dSmrg   if (TREE_CODE (*tp) == PARM_DECL)
853*8feb0f0bSmrg     {
854*8feb0f0bSmrg       pbr = info->adjustments->get_expr_replacement (*tp, true);
855*8feb0f0bSmrg       if (pbr)
856*8feb0f0bSmrg 	repl = pbr->repl;
857*8feb0f0bSmrg     }
858c0a68be4Smrg   else if (TYPE_P (*tp))
8591debfc3dSmrg     *walk_subtrees = 0;
8601debfc3dSmrg 
861*8feb0f0bSmrg   if (repl)
862*8feb0f0bSmrg     repl = unshare_expr (repl);
8631debfc3dSmrg   else
8641debfc3dSmrg     {
8651debfc3dSmrg       if (tp != orig_tp)
8661debfc3dSmrg 	{
8671debfc3dSmrg 	  *walk_subtrees = 0;
8681debfc3dSmrg 	  bool modified = info->modified;
8691debfc3dSmrg 	  info->modified = false;
8701debfc3dSmrg 	  walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset);
8711debfc3dSmrg 	  if (!info->modified)
8721debfc3dSmrg 	    {
8731debfc3dSmrg 	      info->modified = modified;
8741debfc3dSmrg 	      return NULL_TREE;
8751debfc3dSmrg 	    }
8761debfc3dSmrg 	  info->modified = modified;
8771debfc3dSmrg 	  repl = *tp;
8781debfc3dSmrg 	}
8791debfc3dSmrg       else
8801debfc3dSmrg 	return NULL_TREE;
8811debfc3dSmrg     }
8821debfc3dSmrg 
8831debfc3dSmrg   if (tp != orig_tp)
8841debfc3dSmrg     {
885a05ac97eSmrg       if (gimple_code (info->stmt) == GIMPLE_PHI
886*8feb0f0bSmrg 	  && pbr
887a05ac97eSmrg 	  && TREE_CODE (*orig_tp) == ADDR_EXPR
888a05ac97eSmrg 	  && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL
889*8feb0f0bSmrg 	  && pbr->dummy)
890a05ac97eSmrg 	{
891*8feb0f0bSmrg 	  gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME);
892*8feb0f0bSmrg 	  *orig_tp = pbr->dummy;
893a05ac97eSmrg 	  info->modified = true;
894a05ac97eSmrg 	  return NULL_TREE;
895a05ac97eSmrg 	}
896a05ac97eSmrg 
8971debfc3dSmrg       repl = build_fold_addr_expr (repl);
8981debfc3dSmrg       gimple *stmt;
8991debfc3dSmrg       if (is_gimple_debug (info->stmt))
9001debfc3dSmrg 	{
9011debfc3dSmrg 	  tree vexpr = make_node (DEBUG_EXPR_DECL);
9021debfc3dSmrg 	  stmt = gimple_build_debug_source_bind (vexpr, repl, NULL);
9031debfc3dSmrg 	  DECL_ARTIFICIAL (vexpr) = 1;
9041debfc3dSmrg 	  TREE_TYPE (vexpr) = TREE_TYPE (repl);
9051debfc3dSmrg 	  SET_DECL_MODE (vexpr, TYPE_MODE (TREE_TYPE (repl)));
9061debfc3dSmrg 	  repl = vexpr;
9071debfc3dSmrg 	}
9081debfc3dSmrg       else
9091debfc3dSmrg 	{
9101debfc3dSmrg 	  stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
9111debfc3dSmrg 	  repl = gimple_assign_lhs (stmt);
9121debfc3dSmrg 	}
913a05ac97eSmrg       gimple_stmt_iterator gsi;
914a05ac97eSmrg       if (gimple_code (info->stmt) == GIMPLE_PHI)
915a05ac97eSmrg 	{
916*8feb0f0bSmrg 	  if (info->after_stmt)
917*8feb0f0bSmrg 	    gsi = gsi_for_stmt (info->after_stmt);
918*8feb0f0bSmrg 	  else
919a05ac97eSmrg 	    gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
920a05ac97eSmrg 	  /* Cache SSA_NAME for next time.  */
921*8feb0f0bSmrg 	  if (pbr
922a05ac97eSmrg 	      && TREE_CODE (*orig_tp) == ADDR_EXPR
923a05ac97eSmrg 	      && TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL)
924*8feb0f0bSmrg 	    {
925*8feb0f0bSmrg 	      gcc_assert (!pbr->dummy);
926*8feb0f0bSmrg 	      pbr->dummy = repl;
927*8feb0f0bSmrg 	    }
928a05ac97eSmrg 	}
929a05ac97eSmrg       else
930a05ac97eSmrg 	gsi = gsi_for_stmt (info->stmt);
931*8feb0f0bSmrg       if (info->after_stmt)
932*8feb0f0bSmrg 	gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
933*8feb0f0bSmrg       else
9341debfc3dSmrg 	gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
935*8feb0f0bSmrg       if (gimple_code (info->stmt) == GIMPLE_PHI)
936*8feb0f0bSmrg 	info->after_stmt = stmt;
9371debfc3dSmrg       *orig_tp = repl;
9381debfc3dSmrg     }
9391debfc3dSmrg   else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
9401debfc3dSmrg     {
9411debfc3dSmrg       tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
9421debfc3dSmrg       *tp = vce;
9431debfc3dSmrg     }
9441debfc3dSmrg   else
9451debfc3dSmrg     *tp = repl;
9461debfc3dSmrg 
9471debfc3dSmrg   info->modified = true;
9481debfc3dSmrg   return NULL_TREE;
9491debfc3dSmrg }
9501debfc3dSmrg 
9511debfc3dSmrg /* Traverse the function body and perform all modifications as
9521debfc3dSmrg    described in ADJUSTMENTS.  At function return, ADJUSTMENTS will be
9531debfc3dSmrg    modified such that the replacement/reduction value will now be an
9541debfc3dSmrg    offset into the corresponding simd_array.
9551debfc3dSmrg 
9561debfc3dSmrg    This function will replace all function argument uses with their
9571debfc3dSmrg    corresponding simd array elements, and ajust the return values
9581debfc3dSmrg    accordingly.  */
9591debfc3dSmrg 
9601debfc3dSmrg static void
ipa_simd_modify_function_body(struct cgraph_node * node,ipa_param_body_adjustments * adjustments,tree retval_array,tree iter)9611debfc3dSmrg ipa_simd_modify_function_body (struct cgraph_node *node,
962*8feb0f0bSmrg 			       ipa_param_body_adjustments *adjustments,
9631debfc3dSmrg 			       tree retval_array, tree iter)
9641debfc3dSmrg {
9651debfc3dSmrg   basic_block bb;
966*8feb0f0bSmrg   unsigned int i, j;
9671debfc3dSmrg 
968*8feb0f0bSmrg 
969*8feb0f0bSmrg   /* Register replacements for every function argument use to an offset into
970*8feb0f0bSmrg      the corresponding simd_array.  */
9711debfc3dSmrg   for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
9721debfc3dSmrg     {
973*8feb0f0bSmrg       if (!node->simdclone->args[i].vector_arg
974*8feb0f0bSmrg 	  || (*adjustments->m_adj_params)[j].user_flag)
9751debfc3dSmrg 	continue;
9761debfc3dSmrg 
9771debfc3dSmrg       tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
9781debfc3dSmrg       tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
979*8feb0f0bSmrg       tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
980*8feb0f0bSmrg 		  iter, NULL_TREE, NULL_TREE);
981*8feb0f0bSmrg       adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
982*8feb0f0bSmrg 
983*8feb0f0bSmrg       if (simd_clone_subparts (vectype) < node->simdclone->simdlen)
984a2dc1f3fSmrg 	j += node->simdclone->simdlen / simd_clone_subparts (vectype) - 1;
9851debfc3dSmrg     }
9861debfc3dSmrg 
9871debfc3dSmrg   tree name;
9881debfc3dSmrg   FOR_EACH_SSA_NAME (i, name, cfun)
9891debfc3dSmrg     {
9901debfc3dSmrg       tree base_var;
991*8feb0f0bSmrg       if (SSA_NAME_VAR (name)
992*8feb0f0bSmrg 	  && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
993*8feb0f0bSmrg 	  && (base_var
994*8feb0f0bSmrg 	      = adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
9951debfc3dSmrg 	{
9961debfc3dSmrg 	  if (SSA_NAME_IS_DEFAULT_DEF (name))
9971debfc3dSmrg 	    {
998*8feb0f0bSmrg 	      tree old_decl = SSA_NAME_VAR (name);
9991debfc3dSmrg 	      bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
10001debfc3dSmrg 	      gimple_stmt_iterator gsi = gsi_after_labels (bb);
1001*8feb0f0bSmrg 	      tree repl = adjustments->lookup_replacement (old_decl, 0);
1002*8feb0f0bSmrg 	      gcc_checking_assert (repl);
1003*8feb0f0bSmrg 	      repl = unshare_expr (repl);
1004*8feb0f0bSmrg 	      set_ssa_default_def (cfun, old_decl, NULL_TREE);
10051debfc3dSmrg 	      SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
10061debfc3dSmrg 	      SSA_NAME_IS_DEFAULT_DEF (name) = 0;
1007*8feb0f0bSmrg 	      gimple *stmt = gimple_build_assign (name, repl);
10081debfc3dSmrg 	      gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
10091debfc3dSmrg 	    }
10101debfc3dSmrg 	  else
10111debfc3dSmrg 	    SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
10121debfc3dSmrg 	}
10131debfc3dSmrg     }
10141debfc3dSmrg 
10151debfc3dSmrg   struct modify_stmt_info info;
10161debfc3dSmrg   info.adjustments = adjustments;
10171debfc3dSmrg 
10181debfc3dSmrg   FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
10191debfc3dSmrg     {
10201debfc3dSmrg       gimple_stmt_iterator gsi;
10211debfc3dSmrg 
1022a05ac97eSmrg       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1023a05ac97eSmrg 	{
1024a05ac97eSmrg 	  gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
1025a05ac97eSmrg 	  int i, n = gimple_phi_num_args (phi);
1026a05ac97eSmrg 	  info.stmt = phi;
1027*8feb0f0bSmrg 	  info.after_stmt = NULL;
1028a05ac97eSmrg 	  struct walk_stmt_info wi;
1029a05ac97eSmrg 	  memset (&wi, 0, sizeof (wi));
1030a05ac97eSmrg 	  info.modified = false;
1031a05ac97eSmrg 	  wi.info = &info;
1032a05ac97eSmrg 	  for (i = 0; i < n; ++i)
1033a05ac97eSmrg 	    {
1034a05ac97eSmrg 	      int walk_subtrees = 1;
1035a05ac97eSmrg 	      tree arg = gimple_phi_arg_def (phi, i);
1036a05ac97eSmrg 	      tree op = arg;
1037a05ac97eSmrg 	      ipa_simd_modify_stmt_ops (&op, &walk_subtrees, &wi);
1038a05ac97eSmrg 	      if (op != arg)
1039a05ac97eSmrg 		{
1040a05ac97eSmrg 		  SET_PHI_ARG_DEF (phi, i, op);
1041a05ac97eSmrg 		  gcc_assert (TREE_CODE (op) == SSA_NAME);
1042a05ac97eSmrg 		  if (gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL)
1043a05ac97eSmrg 		    SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
1044a05ac97eSmrg 		}
1045a05ac97eSmrg 	    }
1046a05ac97eSmrg 	}
1047a05ac97eSmrg 
10481debfc3dSmrg       gsi = gsi_start_bb (bb);
10491debfc3dSmrg       while (!gsi_end_p (gsi))
10501debfc3dSmrg 	{
10511debfc3dSmrg 	  gimple *stmt = gsi_stmt (gsi);
10521debfc3dSmrg 	  info.stmt = stmt;
1053*8feb0f0bSmrg 	  info.after_stmt = NULL;
10541debfc3dSmrg 	  struct walk_stmt_info wi;
10551debfc3dSmrg 
10561debfc3dSmrg 	  memset (&wi, 0, sizeof (wi));
10571debfc3dSmrg 	  info.modified = false;
10581debfc3dSmrg 	  wi.info = &info;
10591debfc3dSmrg 	  walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
10601debfc3dSmrg 
10611debfc3dSmrg 	  if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
10621debfc3dSmrg 	    {
10631debfc3dSmrg 	      tree retval = gimple_return_retval (return_stmt);
1064a05ac97eSmrg 	      edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
1065a05ac97eSmrg 	      e->flags |= EDGE_FALLTHRU;
10661debfc3dSmrg 	      if (!retval)
10671debfc3dSmrg 		{
10681debfc3dSmrg 		  gsi_remove (&gsi, true);
10691debfc3dSmrg 		  continue;
10701debfc3dSmrg 		}
10711debfc3dSmrg 
10721debfc3dSmrg 	      /* Replace `return foo' with `retval_array[iter] = foo'.  */
10731debfc3dSmrg 	      tree ref = build4 (ARRAY_REF, TREE_TYPE (retval),
10741debfc3dSmrg 				 retval_array, iter, NULL, NULL);
10751debfc3dSmrg 	      stmt = gimple_build_assign (ref, retval);
10761debfc3dSmrg 	      gsi_replace (&gsi, stmt, true);
10771debfc3dSmrg 	      info.modified = true;
10781debfc3dSmrg 	    }
10791debfc3dSmrg 
10801debfc3dSmrg 	  if (info.modified)
10811debfc3dSmrg 	    {
10821debfc3dSmrg 	      update_stmt (stmt);
1083a2dc1f3fSmrg 	      /* If the above changed the var of a debug bind into something
1084a2dc1f3fSmrg 		 different, remove the debug stmt.  We could also for all the
1085a2dc1f3fSmrg 		 replaced parameters add VAR_DECLs for debug info purposes,
1086a2dc1f3fSmrg 		 add debug stmts for those to be the simd array accesses and
1087a2dc1f3fSmrg 		 replace debug stmt var operand with that var.  Debugging of
1088a2dc1f3fSmrg 		 vectorized loops doesn't work too well, so don't bother for
1089a2dc1f3fSmrg 		 now.  */
1090a2dc1f3fSmrg 	      if ((gimple_debug_bind_p (stmt)
1091a2dc1f3fSmrg 		   && !DECL_P (gimple_debug_bind_get_var (stmt)))
1092a2dc1f3fSmrg 		  || (gimple_debug_source_bind_p (stmt)
1093a2dc1f3fSmrg 		      && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
1094a2dc1f3fSmrg 		{
1095a2dc1f3fSmrg 		  gsi_remove (&gsi, true);
1096a2dc1f3fSmrg 		  continue;
1097a2dc1f3fSmrg 		}
10981debfc3dSmrg 	      if (maybe_clean_eh_stmt (stmt))
10991debfc3dSmrg 		gimple_purge_dead_eh_edges (gimple_bb (stmt));
11001debfc3dSmrg 	    }
11011debfc3dSmrg 	  gsi_next (&gsi);
11021debfc3dSmrg 	}
11031debfc3dSmrg     }
11041debfc3dSmrg }
11051debfc3dSmrg 
11061debfc3dSmrg /* Helper function of simd_clone_adjust, return linear step addend
11071debfc3dSmrg    of Ith argument.  */
11081debfc3dSmrg 
11091debfc3dSmrg static tree
simd_clone_linear_addend(struct cgraph_node * node,unsigned int i,tree addtype,basic_block entry_bb)11101debfc3dSmrg simd_clone_linear_addend (struct cgraph_node *node, unsigned int i,
11111debfc3dSmrg 			  tree addtype, basic_block entry_bb)
11121debfc3dSmrg {
11131debfc3dSmrg   tree ptype = NULL_TREE;
11141debfc3dSmrg   switch (node->simdclone->args[i].arg_type)
11151debfc3dSmrg     {
11161debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
11171debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
11181debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
11191debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
11201debfc3dSmrg       return build_int_cst (addtype, node->simdclone->args[i].linear_step);
11211debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
11221debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
11231debfc3dSmrg       ptype = TREE_TYPE (node->simdclone->args[i].orig_arg);
11241debfc3dSmrg       break;
11251debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
11261debfc3dSmrg     case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
11271debfc3dSmrg       ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg));
11281debfc3dSmrg       break;
11291debfc3dSmrg     default:
11301debfc3dSmrg       gcc_unreachable ();
11311debfc3dSmrg     }
11321debfc3dSmrg 
11331debfc3dSmrg   unsigned int idx = node->simdclone->args[i].linear_step;
11341debfc3dSmrg   tree arg = node->simdclone->args[idx].orig_arg;
11351debfc3dSmrg   gcc_assert (is_gimple_reg_type (TREE_TYPE (arg)));
11361debfc3dSmrg   gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
11371debfc3dSmrg   gimple *g;
11381debfc3dSmrg   tree ret;
11391debfc3dSmrg   if (is_gimple_reg (arg))
11401debfc3dSmrg     ret = get_or_create_ssa_default_def (cfun, arg);
11411debfc3dSmrg   else
11421debfc3dSmrg     {
11431debfc3dSmrg       g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
11441debfc3dSmrg       gsi_insert_before (&gsi, g, GSI_SAME_STMT);
11451debfc3dSmrg       ret = gimple_assign_lhs (g);
11461debfc3dSmrg     }
11471debfc3dSmrg   if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
11481debfc3dSmrg     {
11491debfc3dSmrg       g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))),
11501debfc3dSmrg 			       build_simple_mem_ref (ret));
11511debfc3dSmrg       gsi_insert_before (&gsi, g, GSI_SAME_STMT);
11521debfc3dSmrg       ret = gimple_assign_lhs (g);
11531debfc3dSmrg     }
11541debfc3dSmrg   if (!useless_type_conversion_p (addtype, TREE_TYPE (ret)))
11551debfc3dSmrg     {
11561debfc3dSmrg       g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret);
11571debfc3dSmrg       gsi_insert_before (&gsi, g, GSI_SAME_STMT);
11581debfc3dSmrg       ret = gimple_assign_lhs (g);
11591debfc3dSmrg     }
11601debfc3dSmrg   if (POINTER_TYPE_P (ptype))
11611debfc3dSmrg     {
11621debfc3dSmrg       tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype));
11631debfc3dSmrg       if (size && TREE_CODE (size) == INTEGER_CST)
11641debfc3dSmrg 	{
11651debfc3dSmrg 	  g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR,
11661debfc3dSmrg 				   ret, fold_convert (addtype, size));
11671debfc3dSmrg 	  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
11681debfc3dSmrg 	  ret = gimple_assign_lhs (g);
11691debfc3dSmrg 	}
11701debfc3dSmrg     }
11711debfc3dSmrg   return ret;
11721debfc3dSmrg }
11731debfc3dSmrg 
11741debfc3dSmrg /* Adjust the argument types in NODE to their appropriate vector
11751debfc3dSmrg    counterparts.  */
11761debfc3dSmrg 
11771debfc3dSmrg static void
simd_clone_adjust(struct cgraph_node * node)11781debfc3dSmrg simd_clone_adjust (struct cgraph_node *node)
11791debfc3dSmrg {
11801debfc3dSmrg   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
11811debfc3dSmrg 
1182c0a68be4Smrg   TREE_TYPE (node->decl) = build_distinct_type_copy (TREE_TYPE (node->decl));
11831debfc3dSmrg   targetm.simd_clone.adjust (node);
11841debfc3dSmrg 
11851debfc3dSmrg   tree retval = simd_clone_adjust_return_type (node);
1186*8feb0f0bSmrg   ipa_param_body_adjustments *adjustments
11871debfc3dSmrg     = simd_clone_adjust_argument_types (node);
1188*8feb0f0bSmrg   gcc_assert (adjustments);
11891debfc3dSmrg 
11901debfc3dSmrg   push_gimplify_context ();
11911debfc3dSmrg 
11921debfc3dSmrg   gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments);
11931debfc3dSmrg 
11941debfc3dSmrg   /* Adjust all uses of vector arguments accordingly.  Adjust all
11951debfc3dSmrg      return values accordingly.  */
11961debfc3dSmrg   tree iter = create_tmp_var (unsigned_type_node, "iter");
11971debfc3dSmrg   tree iter1 = make_ssa_name (iter);
11981debfc3dSmrg   tree iter2 = NULL_TREE;
11991debfc3dSmrg   ipa_simd_modify_function_body (node, adjustments, retval, iter1);
1200*8feb0f0bSmrg   delete adjustments;
12011debfc3dSmrg 
12021debfc3dSmrg   /* Initialize the iteration variable.  */
12031debfc3dSmrg   basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
12041debfc3dSmrg   basic_block body_bb = split_block_after_labels (entry_bb)->dest;
12051debfc3dSmrg   gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
12061debfc3dSmrg   /* Insert the SIMD array and iv initialization at function
12071debfc3dSmrg      entry.  */
12081debfc3dSmrg   gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
12091debfc3dSmrg 
12101debfc3dSmrg   pop_gimplify_context (NULL);
12111debfc3dSmrg 
12121debfc3dSmrg   gimple *g;
12131debfc3dSmrg   basic_block incr_bb = NULL;
1214*8feb0f0bSmrg   class loop *loop = NULL;
12151debfc3dSmrg 
12161debfc3dSmrg   /* Create a new BB right before the original exit BB, to hold the
12171debfc3dSmrg      iteration increment and the condition/branch.  */
12181debfc3dSmrg   if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
12191debfc3dSmrg     {
12201debfc3dSmrg       basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
12211debfc3dSmrg       incr_bb = create_empty_bb (orig_exit);
1222a2dc1f3fSmrg       incr_bb->count = profile_count::zero ();
12231debfc3dSmrg       add_bb_to_loop (incr_bb, body_bb->loop_father);
1224a05ac97eSmrg       while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
12251debfc3dSmrg 	{
1226a05ac97eSmrg 	  edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
12271debfc3dSmrg 	  redirect_edge_succ (e, incr_bb);
1228a2dc1f3fSmrg 	  incr_bb->count += e->count ();
12291debfc3dSmrg 	}
12301debfc3dSmrg     }
12311debfc3dSmrg   else if (node->simdclone->inbranch)
12321debfc3dSmrg     {
12331debfc3dSmrg       incr_bb = create_empty_bb (entry_bb);
1234a2dc1f3fSmrg       incr_bb->count = profile_count::zero ();
12351debfc3dSmrg       add_bb_to_loop (incr_bb, body_bb->loop_father);
12361debfc3dSmrg     }
12371debfc3dSmrg 
12381debfc3dSmrg   if (incr_bb)
12391debfc3dSmrg     {
1240a2dc1f3fSmrg       make_single_succ_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
12411debfc3dSmrg       gsi = gsi_last_bb (incr_bb);
12421debfc3dSmrg       iter2 = make_ssa_name (iter);
12431debfc3dSmrg       g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
12441debfc3dSmrg 			       build_int_cst (unsigned_type_node, 1));
12451debfc3dSmrg       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
12461debfc3dSmrg 
12471debfc3dSmrg       /* Mostly annotate the loop for the vectorizer (the rest is done
12481debfc3dSmrg 	 below).  */
12491debfc3dSmrg       loop = alloc_loop ();
12501debfc3dSmrg       cfun->has_force_vectorize_loops = true;
12511debfc3dSmrg       loop->safelen = node->simdclone->simdlen;
12521debfc3dSmrg       loop->force_vectorize = true;
12531debfc3dSmrg       loop->header = body_bb;
12541debfc3dSmrg     }
12551debfc3dSmrg 
12561debfc3dSmrg   /* Branch around the body if the mask applies.  */
12571debfc3dSmrg   if (node->simdclone->inbranch)
12581debfc3dSmrg     {
12591debfc3dSmrg       gsi = gsi_last_bb (loop->header);
12601debfc3dSmrg       tree mask_array
12611debfc3dSmrg 	= node->simdclone->args[node->simdclone->nargs - 1].simd_array;
12621debfc3dSmrg       tree mask;
12631debfc3dSmrg       if (node->simdclone->mask_mode != VOIDmode)
12641debfc3dSmrg 	{
12651debfc3dSmrg 	  tree shift_cnt;
12661debfc3dSmrg 	  if (mask_array == NULL_TREE)
12671debfc3dSmrg 	    {
12681debfc3dSmrg 	      tree arg = node->simdclone->args[node->simdclone->nargs
12691debfc3dSmrg 					       - 1].vector_arg;
12701debfc3dSmrg 	      mask = get_or_create_ssa_default_def (cfun, arg);
12711debfc3dSmrg 	      shift_cnt = iter1;
12721debfc3dSmrg 	    }
12731debfc3dSmrg 	  else
12741debfc3dSmrg 	    {
12751debfc3dSmrg 	      tree maskt = TREE_TYPE (mask_array);
12761debfc3dSmrg 	      int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt)));
12771debfc3dSmrg 	      c = node->simdclone->simdlen / (c + 1);
12781debfc3dSmrg 	      int s = exact_log2 (c);
12791debfc3dSmrg 	      gcc_assert (s > 0);
12801debfc3dSmrg 	      c--;
12811debfc3dSmrg 	      tree idx = make_ssa_name (TREE_TYPE (iter1));
12821debfc3dSmrg 	      g = gimple_build_assign (idx, RSHIFT_EXPR, iter1,
12831debfc3dSmrg 				       build_int_cst (NULL_TREE, s));
12841debfc3dSmrg 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
12851debfc3dSmrg 	      mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
12861debfc3dSmrg 	      tree aref = build4 (ARRAY_REF,
12871debfc3dSmrg 				  TREE_TYPE (TREE_TYPE (mask_array)),
12881debfc3dSmrg 				  mask_array, idx, NULL, NULL);
12891debfc3dSmrg 	      g = gimple_build_assign (mask, aref);
12901debfc3dSmrg 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
12911debfc3dSmrg 	      shift_cnt = make_ssa_name (TREE_TYPE (iter1));
12921debfc3dSmrg 	      g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1,
12931debfc3dSmrg 				       build_int_cst (TREE_TYPE (iter1), c));
12941debfc3dSmrg 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
12951debfc3dSmrg 	    }
12961debfc3dSmrg 	  g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
12971debfc3dSmrg 				   RSHIFT_EXPR, mask, shift_cnt);
12981debfc3dSmrg 	  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
12991debfc3dSmrg 	  mask = gimple_assign_lhs (g);
13001debfc3dSmrg 	  g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
13011debfc3dSmrg 				   BIT_AND_EXPR, mask,
13021debfc3dSmrg 				   build_int_cst (TREE_TYPE (mask), 1));
13031debfc3dSmrg 	  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
13041debfc3dSmrg 	  mask = gimple_assign_lhs (g);
13051debfc3dSmrg 	}
13061debfc3dSmrg       else
13071debfc3dSmrg 	{
13081debfc3dSmrg 	  mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
13091debfc3dSmrg 	  tree aref = build4 (ARRAY_REF,
13101debfc3dSmrg 			      TREE_TYPE (TREE_TYPE (mask_array)),
13111debfc3dSmrg 			      mask_array, iter1, NULL, NULL);
13121debfc3dSmrg 	  g = gimple_build_assign (mask, aref);
13131debfc3dSmrg 	  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1314a2dc1f3fSmrg 	  int bitsize = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (aref)));
13151debfc3dSmrg 	  if (!INTEGRAL_TYPE_P (TREE_TYPE (aref)))
13161debfc3dSmrg 	    {
13171debfc3dSmrg 	      aref = build1 (VIEW_CONVERT_EXPR,
13181debfc3dSmrg 			     build_nonstandard_integer_type (bitsize, 0),
13191debfc3dSmrg 							     mask);
13201debfc3dSmrg 	      mask = make_ssa_name (TREE_TYPE (aref));
13211debfc3dSmrg 	      g = gimple_build_assign (mask, aref);
13221debfc3dSmrg 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
13231debfc3dSmrg 	    }
13241debfc3dSmrg 	}
13251debfc3dSmrg 
13261debfc3dSmrg       g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)),
13271debfc3dSmrg 			     NULL, NULL);
13281debfc3dSmrg       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
1329a2dc1f3fSmrg       edge e = make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE);
1330a2dc1f3fSmrg       e->probability = profile_probability::unlikely ().guessed ();
1331a2dc1f3fSmrg       incr_bb->count += e->count ();
1332a2dc1f3fSmrg       edge fallthru = FALLTHRU_EDGE (loop->header);
1333a2dc1f3fSmrg       fallthru->flags = EDGE_FALSE_VALUE;
1334a2dc1f3fSmrg       fallthru->probability = profile_probability::likely ().guessed ();
13351debfc3dSmrg     }
13361debfc3dSmrg 
13371debfc3dSmrg   basic_block latch_bb = NULL;
13381debfc3dSmrg   basic_block new_exit_bb = NULL;
13391debfc3dSmrg 
13401debfc3dSmrg   /* Generate the condition.  */
13411debfc3dSmrg   if (incr_bb)
13421debfc3dSmrg     {
13431debfc3dSmrg       gsi = gsi_last_bb (incr_bb);
13441debfc3dSmrg       g = gimple_build_cond (LT_EXPR, iter2,
13451debfc3dSmrg 			     build_int_cst (unsigned_type_node,
13461debfc3dSmrg 					    node->simdclone->simdlen),
13471debfc3dSmrg 			     NULL, NULL);
13481debfc3dSmrg       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
13491debfc3dSmrg       edge e = split_block (incr_bb, gsi_stmt (gsi));
13501debfc3dSmrg       latch_bb = e->dest;
13511debfc3dSmrg       new_exit_bb = split_block_after_labels (latch_bb)->dest;
13521debfc3dSmrg       loop->latch = latch_bb;
13531debfc3dSmrg 
13541debfc3dSmrg       redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
13551debfc3dSmrg 
1356a2dc1f3fSmrg       edge new_e = make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
1357a2dc1f3fSmrg 
1358a2dc1f3fSmrg       /* FIXME: Do we need to distribute probabilities for the conditional? */
1359a2dc1f3fSmrg       new_e->probability = profile_probability::guessed_never ();
13601debfc3dSmrg       /* The successor of incr_bb is already pointing to latch_bb; just
13611debfc3dSmrg 	 change the flags.
13621debfc3dSmrg 	 make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE);  */
13631debfc3dSmrg       FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
13641debfc3dSmrg     }
13651debfc3dSmrg 
13661debfc3dSmrg   gphi *phi = create_phi_node (iter1, body_bb);
13671debfc3dSmrg   edge preheader_edge = find_edge (entry_bb, body_bb);
13681debfc3dSmrg   edge latch_edge = NULL;
13691debfc3dSmrg   add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
13701debfc3dSmrg 	       UNKNOWN_LOCATION);
13711debfc3dSmrg   if (incr_bb)
13721debfc3dSmrg     {
13731debfc3dSmrg       latch_edge = single_succ_edge (latch_bb);
13741debfc3dSmrg       add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
13751debfc3dSmrg 
13761debfc3dSmrg       /* Generate the new return.  */
13771debfc3dSmrg       gsi = gsi_last_bb (new_exit_bb);
13781debfc3dSmrg       if (retval
13791debfc3dSmrg 	  && TREE_CODE (retval) == VIEW_CONVERT_EXPR
13801debfc3dSmrg 	  && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
13811debfc3dSmrg 	retval = TREE_OPERAND (retval, 0);
13821debfc3dSmrg       else if (retval)
13831debfc3dSmrg 	{
13841debfc3dSmrg 	  retval = build1 (VIEW_CONVERT_EXPR,
13851debfc3dSmrg 			   TREE_TYPE (TREE_TYPE (node->decl)),
13861debfc3dSmrg 			   retval);
13871debfc3dSmrg 	  retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
13881debfc3dSmrg 					     false, GSI_CONTINUE_LINKING);
13891debfc3dSmrg 	}
13901debfc3dSmrg       g = gimple_build_return (retval);
13911debfc3dSmrg       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
13921debfc3dSmrg     }
13931debfc3dSmrg 
13941debfc3dSmrg   /* Handle aligned clauses by replacing default defs of the aligned
13951debfc3dSmrg      uniform args with __builtin_assume_aligned (arg_N(D), alignment)
13961debfc3dSmrg      lhs.  Handle linear by adding PHIs.  */
13971debfc3dSmrg   for (unsigned i = 0; i < node->simdclone->nargs; i++)
13981debfc3dSmrg     if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
13991debfc3dSmrg 	&& (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg)
14001debfc3dSmrg 	    || !is_gimple_reg_type
14011debfc3dSmrg 			(TREE_TYPE (node->simdclone->args[i].orig_arg))))
14021debfc3dSmrg       {
14031debfc3dSmrg 	tree orig_arg = node->simdclone->args[i].orig_arg;
14041debfc3dSmrg 	if (is_gimple_reg_type (TREE_TYPE (orig_arg)))
14051debfc3dSmrg 	  iter1 = make_ssa_name (TREE_TYPE (orig_arg));
14061debfc3dSmrg 	else
14071debfc3dSmrg 	  {
14081debfc3dSmrg 	    iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg));
14091debfc3dSmrg 	    gimple_add_tmp_var (iter1);
14101debfc3dSmrg 	  }
14111debfc3dSmrg 	gsi = gsi_after_labels (entry_bb);
14121debfc3dSmrg 	g = gimple_build_assign (iter1, orig_arg);
14131debfc3dSmrg 	gsi_insert_before (&gsi, g, GSI_NEW_STMT);
14141debfc3dSmrg 	gsi = gsi_after_labels (body_bb);
14151debfc3dSmrg 	g = gimple_build_assign (orig_arg, iter1);
14161debfc3dSmrg 	gsi_insert_before (&gsi, g, GSI_NEW_STMT);
14171debfc3dSmrg       }
14181debfc3dSmrg     else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
14191debfc3dSmrg 	     && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg)
14201debfc3dSmrg 	     && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
14211debfc3dSmrg 		== REFERENCE_TYPE
14221debfc3dSmrg 	     && TREE_ADDRESSABLE
14231debfc3dSmrg 		  (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg))))
14241debfc3dSmrg       {
14251debfc3dSmrg 	tree orig_arg = node->simdclone->args[i].orig_arg;
14261debfc3dSmrg 	tree def = ssa_default_def (cfun, orig_arg);
14271debfc3dSmrg 	if (def && !has_zero_uses (def))
14281debfc3dSmrg 	  {
14291debfc3dSmrg 	    iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg)));
14301debfc3dSmrg 	    gimple_add_tmp_var (iter1);
14311debfc3dSmrg 	    gsi = gsi_after_labels (entry_bb);
14321debfc3dSmrg 	    g = gimple_build_assign (iter1, build_simple_mem_ref (def));
14331debfc3dSmrg 	    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
14341debfc3dSmrg 	    gsi = gsi_after_labels (body_bb);
14351debfc3dSmrg 	    g = gimple_build_assign (build_simple_mem_ref (def), iter1);
14361debfc3dSmrg 	    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
14371debfc3dSmrg 	  }
14381debfc3dSmrg       }
14391debfc3dSmrg     else if (node->simdclone->args[i].alignment
14401debfc3dSmrg 	     && node->simdclone->args[i].arg_type
14411debfc3dSmrg 		== SIMD_CLONE_ARG_TYPE_UNIFORM
14421debfc3dSmrg 	     && (node->simdclone->args[i].alignment
14431debfc3dSmrg 		 & (node->simdclone->args[i].alignment - 1)) == 0
14441debfc3dSmrg 	     && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
14451debfc3dSmrg 		== POINTER_TYPE)
14461debfc3dSmrg       {
14471debfc3dSmrg 	unsigned int alignment = node->simdclone->args[i].alignment;
14481debfc3dSmrg 	tree orig_arg = node->simdclone->args[i].orig_arg;
14491debfc3dSmrg 	tree def = ssa_default_def (cfun, orig_arg);
14501debfc3dSmrg 	if (def && !has_zero_uses (def))
14511debfc3dSmrg 	  {
14521debfc3dSmrg 	    tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
14531debfc3dSmrg 	    gimple_seq seq = NULL;
14541debfc3dSmrg 	    bool need_cvt = false;
14551debfc3dSmrg 	    gcall *call
14561debfc3dSmrg 	      = gimple_build_call (fn, 2, def, size_int (alignment));
14571debfc3dSmrg 	    g = call;
14581debfc3dSmrg 	    if (!useless_type_conversion_p (TREE_TYPE (orig_arg),
14591debfc3dSmrg 					    ptr_type_node))
14601debfc3dSmrg 	      need_cvt = true;
14611debfc3dSmrg 	    tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg);
14621debfc3dSmrg 	    gimple_call_set_lhs (g, t);
14631debfc3dSmrg 	    gimple_seq_add_stmt_without_update (&seq, g);
14641debfc3dSmrg 	    if (need_cvt)
14651debfc3dSmrg 	      {
14661debfc3dSmrg 		t = make_ssa_name (orig_arg);
14671debfc3dSmrg 		g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g));
14681debfc3dSmrg 		gimple_seq_add_stmt_without_update (&seq, g);
14691debfc3dSmrg 	      }
14701debfc3dSmrg 	    gsi_insert_seq_on_edge_immediate
14711debfc3dSmrg 	      (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
14721debfc3dSmrg 
14731debfc3dSmrg 	    entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
14741debfc3dSmrg 	    node->create_edge (cgraph_node::get_create (fn),
1475a2dc1f3fSmrg 			       call, entry_bb->count);
14761debfc3dSmrg 
14771debfc3dSmrg 	    imm_use_iterator iter;
14781debfc3dSmrg 	    use_operand_p use_p;
14791debfc3dSmrg 	    gimple *use_stmt;
14801debfc3dSmrg 	    tree repl = gimple_get_lhs (g);
14811debfc3dSmrg 	    FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
14821debfc3dSmrg 	      if (is_gimple_debug (use_stmt) || use_stmt == call)
14831debfc3dSmrg 		continue;
14841debfc3dSmrg 	      else
14851debfc3dSmrg 		FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
14861debfc3dSmrg 		  SET_USE (use_p, repl);
14871debfc3dSmrg 	  }
14881debfc3dSmrg       }
14891debfc3dSmrg     else if ((node->simdclone->args[i].arg_type
14901debfc3dSmrg 	      == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
14911debfc3dSmrg 	     || (node->simdclone->args[i].arg_type
14921debfc3dSmrg 		 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
14931debfc3dSmrg 	     || (node->simdclone->args[i].arg_type
14941debfc3dSmrg 		 == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP)
14951debfc3dSmrg 	     || (node->simdclone->args[i].arg_type
14961debfc3dSmrg 		 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP))
14971debfc3dSmrg       {
14981debfc3dSmrg 	tree orig_arg = node->simdclone->args[i].orig_arg;
14991debfc3dSmrg 	gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
15001debfc3dSmrg 		    || POINTER_TYPE_P (TREE_TYPE (orig_arg)));
15011debfc3dSmrg 	tree def = NULL_TREE;
15021debfc3dSmrg 	if (TREE_ADDRESSABLE (orig_arg))
15031debfc3dSmrg 	  {
15041debfc3dSmrg 	    def = make_ssa_name (TREE_TYPE (orig_arg));
15051debfc3dSmrg 	    iter1 = make_ssa_name (TREE_TYPE (orig_arg));
15061debfc3dSmrg 	    if (incr_bb)
15071debfc3dSmrg 	      iter2 = make_ssa_name (TREE_TYPE (orig_arg));
15081debfc3dSmrg 	    gsi = gsi_after_labels (entry_bb);
15091debfc3dSmrg 	    g = gimple_build_assign (def, orig_arg);
15101debfc3dSmrg 	    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
15111debfc3dSmrg 	  }
15121debfc3dSmrg 	else
15131debfc3dSmrg 	  {
15141debfc3dSmrg 	    def = ssa_default_def (cfun, orig_arg);
15151debfc3dSmrg 	    if (!def || has_zero_uses (def))
15161debfc3dSmrg 	      def = NULL_TREE;
15171debfc3dSmrg 	    else
15181debfc3dSmrg 	      {
15191debfc3dSmrg 		iter1 = make_ssa_name (orig_arg);
15201debfc3dSmrg 		if (incr_bb)
15211debfc3dSmrg 		  iter2 = make_ssa_name (orig_arg);
15221debfc3dSmrg 	      }
15231debfc3dSmrg 	  }
15241debfc3dSmrg 	if (def)
15251debfc3dSmrg 	  {
15261debfc3dSmrg 	    phi = create_phi_node (iter1, body_bb);
15271debfc3dSmrg 	    add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
15281debfc3dSmrg 	    if (incr_bb)
15291debfc3dSmrg 	      {
15301debfc3dSmrg 		add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
15311debfc3dSmrg 		enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
15321debfc3dSmrg 				      ? PLUS_EXPR : POINTER_PLUS_EXPR;
15331debfc3dSmrg 		tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
15341debfc3dSmrg 			       ? TREE_TYPE (orig_arg) : sizetype;
15351debfc3dSmrg 		tree addcst = simd_clone_linear_addend (node, i, addtype,
15361debfc3dSmrg 							entry_bb);
15371debfc3dSmrg 		gsi = gsi_last_bb (incr_bb);
15381debfc3dSmrg 		g = gimple_build_assign (iter2, code, iter1, addcst);
15391debfc3dSmrg 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
15401debfc3dSmrg 	      }
15411debfc3dSmrg 
15421debfc3dSmrg 	    imm_use_iterator iter;
15431debfc3dSmrg 	    use_operand_p use_p;
15441debfc3dSmrg 	    gimple *use_stmt;
15451debfc3dSmrg 	    if (TREE_ADDRESSABLE (orig_arg))
15461debfc3dSmrg 	      {
15471debfc3dSmrg 		gsi = gsi_after_labels (body_bb);
15481debfc3dSmrg 		g = gimple_build_assign (orig_arg, iter1);
15491debfc3dSmrg 		gsi_insert_before (&gsi, g, GSI_NEW_STMT);
15501debfc3dSmrg 	      }
15511debfc3dSmrg 	    else
15521debfc3dSmrg 	      FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
15531debfc3dSmrg 		if (use_stmt == phi)
15541debfc3dSmrg 		  continue;
15551debfc3dSmrg 		else
15561debfc3dSmrg 		  FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
15571debfc3dSmrg 		    SET_USE (use_p, iter1);
15581debfc3dSmrg 	  }
15591debfc3dSmrg       }
15601debfc3dSmrg     else if (node->simdclone->args[i].arg_type
15611debfc3dSmrg 	     == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP
15621debfc3dSmrg 	     || (node->simdclone->args[i].arg_type
15631debfc3dSmrg 		 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP))
15641debfc3dSmrg       {
15651debfc3dSmrg 	tree orig_arg = node->simdclone->args[i].orig_arg;
15661debfc3dSmrg 	tree def = ssa_default_def (cfun, orig_arg);
15671debfc3dSmrg 	gcc_assert (!TREE_ADDRESSABLE (orig_arg)
15681debfc3dSmrg 		    && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE);
15691debfc3dSmrg 	if (def && !has_zero_uses (def))
15701debfc3dSmrg 	  {
15711debfc3dSmrg 	    tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
15721debfc3dSmrg 	    iter1 = make_ssa_name (orig_arg);
15731debfc3dSmrg 	    if (incr_bb)
15741debfc3dSmrg 	      iter2 = make_ssa_name (orig_arg);
15751debfc3dSmrg 	    tree iter3 = make_ssa_name (rtype);
15761debfc3dSmrg 	    tree iter4 = make_ssa_name (rtype);
15771debfc3dSmrg 	    tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
15781debfc3dSmrg 	    gsi = gsi_after_labels (entry_bb);
15791debfc3dSmrg 	    gimple *load
15801debfc3dSmrg 	      = gimple_build_assign (iter3, build_simple_mem_ref (def));
15811debfc3dSmrg 	    gsi_insert_before (&gsi, load, GSI_NEW_STMT);
15821debfc3dSmrg 
15831debfc3dSmrg 	    tree array = node->simdclone->args[i].simd_array;
15841debfc3dSmrg 	    TREE_ADDRESSABLE (array) = 1;
15851debfc3dSmrg 	    tree ptr = build_fold_addr_expr (array);
15861debfc3dSmrg 	    phi = create_phi_node (iter1, body_bb);
15871debfc3dSmrg 	    add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
15881debfc3dSmrg 	    if (incr_bb)
15891debfc3dSmrg 	      {
15901debfc3dSmrg 		add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
15911debfc3dSmrg 		g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
15921debfc3dSmrg 					 TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
15931debfc3dSmrg 		gsi = gsi_last_bb (incr_bb);
15941debfc3dSmrg 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
15951debfc3dSmrg 	      }
15961debfc3dSmrg 
15971debfc3dSmrg 	    phi = create_phi_node (iter4, body_bb);
15981debfc3dSmrg 	    add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
15991debfc3dSmrg 	    if (incr_bb)
16001debfc3dSmrg 	      {
16011debfc3dSmrg 		add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
16021debfc3dSmrg 		enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
16031debfc3dSmrg 				      ? PLUS_EXPR : POINTER_PLUS_EXPR;
16041debfc3dSmrg 		tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
16051debfc3dSmrg 			       ? TREE_TYPE (iter3) : sizetype;
16061debfc3dSmrg 		tree addcst = simd_clone_linear_addend (node, i, addtype,
16071debfc3dSmrg 							entry_bb);
16081debfc3dSmrg 		g = gimple_build_assign (iter5, code, iter4, addcst);
16091debfc3dSmrg 		gsi = gsi_last_bb (incr_bb);
16101debfc3dSmrg 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
16111debfc3dSmrg 	      }
16121debfc3dSmrg 
16131debfc3dSmrg 	    g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
16141debfc3dSmrg 	    gsi = gsi_after_labels (body_bb);
16151debfc3dSmrg 	    gsi_insert_before (&gsi, g, GSI_SAME_STMT);
16161debfc3dSmrg 
16171debfc3dSmrg 	    imm_use_iterator iter;
16181debfc3dSmrg 	    use_operand_p use_p;
16191debfc3dSmrg 	    gimple *use_stmt;
16201debfc3dSmrg 	    FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
16211debfc3dSmrg 	      if (use_stmt == load)
16221debfc3dSmrg 		continue;
16231debfc3dSmrg 	      else
16241debfc3dSmrg 		FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
16251debfc3dSmrg 		  SET_USE (use_p, iter1);
16261debfc3dSmrg 
16271debfc3dSmrg 	    if (!TYPE_READONLY (rtype) && incr_bb)
16281debfc3dSmrg 	      {
16291debfc3dSmrg 		tree v = make_ssa_name (rtype);
16301debfc3dSmrg 		tree aref = build4 (ARRAY_REF, rtype, array,
16311debfc3dSmrg 				    size_zero_node, NULL_TREE,
16321debfc3dSmrg 				    NULL_TREE);
16331debfc3dSmrg 		gsi = gsi_after_labels (new_exit_bb);
16341debfc3dSmrg 		g = gimple_build_assign (v, aref);
16351debfc3dSmrg 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
16361debfc3dSmrg 		g = gimple_build_assign (build_simple_mem_ref (def), v);
16371debfc3dSmrg 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
16381debfc3dSmrg 	      }
16391debfc3dSmrg 	  }
16401debfc3dSmrg       }
16411debfc3dSmrg 
16421debfc3dSmrg   calculate_dominance_info (CDI_DOMINATORS);
16431debfc3dSmrg   if (loop)
16441debfc3dSmrg     add_loop (loop, loop->header->loop_father);
16451debfc3dSmrg   update_ssa (TODO_update_ssa);
16461debfc3dSmrg 
16471debfc3dSmrg   pop_cfun ();
16481debfc3dSmrg }
16491debfc3dSmrg 
16501debfc3dSmrg /* If the function in NODE is tagged as an elemental SIMD function,
16511debfc3dSmrg    create the appropriate SIMD clones.  */
16521debfc3dSmrg 
1653a2dc1f3fSmrg void
expand_simd_clones(struct cgraph_node * node)16541debfc3dSmrg expand_simd_clones (struct cgraph_node *node)
16551debfc3dSmrg {
16561debfc3dSmrg   tree attr = lookup_attribute ("omp declare simd",
16571debfc3dSmrg 				DECL_ATTRIBUTES (node->decl));
16581debfc3dSmrg   if (attr == NULL_TREE
1659*8feb0f0bSmrg       || node->inlined_to
16601debfc3dSmrg       || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
16611debfc3dSmrg     return;
16621debfc3dSmrg 
16631debfc3dSmrg   /* Ignore
16641debfc3dSmrg      #pragma omp declare simd
16651debfc3dSmrg      extern int foo ();
16661debfc3dSmrg      in C, there we don't know the argument types at all.  */
16671debfc3dSmrg   if (!node->definition
16681debfc3dSmrg       && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE)
16691debfc3dSmrg     return;
16701debfc3dSmrg 
16711debfc3dSmrg   /* Call this before creating clone_info, as it might ggc_collect.  */
16721debfc3dSmrg   if (node->definition && node->has_gimple_body_p ())
16731debfc3dSmrg     node->get_body ();
16741debfc3dSmrg 
16751debfc3dSmrg   do
16761debfc3dSmrg     {
16771debfc3dSmrg       /* Start with parsing the "omp declare simd" attribute(s).  */
16781debfc3dSmrg       bool inbranch_clause_specified;
16791debfc3dSmrg       struct cgraph_simd_clone *clone_info
16801debfc3dSmrg 	= simd_clone_clauses_extract (node, TREE_VALUE (attr),
16811debfc3dSmrg 				      &inbranch_clause_specified);
16821debfc3dSmrg       if (clone_info == NULL)
16831debfc3dSmrg 	continue;
16841debfc3dSmrg 
16851debfc3dSmrg       int orig_simdlen = clone_info->simdlen;
16861debfc3dSmrg       tree base_type = simd_clone_compute_base_data_type (node, clone_info);
16871debfc3dSmrg       /* The target can return 0 (no simd clones should be created),
16881debfc3dSmrg 	 1 (just one ISA of simd clones should be created) or higher
16891debfc3dSmrg 	 count of ISA variants.  In that case, clone_info is initialized
16901debfc3dSmrg 	 for the first ISA variant.  */
16911debfc3dSmrg       int count
16921debfc3dSmrg 	= targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info,
16931debfc3dSmrg 							  base_type, 0);
16941debfc3dSmrg       if (count == 0)
16951debfc3dSmrg 	continue;
16961debfc3dSmrg 
16971debfc3dSmrg       /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED,
16981debfc3dSmrg 	 also create one inbranch and one !inbranch clone of it.  */
16991debfc3dSmrg       for (int i = 0; i < count * 2; i++)
17001debfc3dSmrg 	{
17011debfc3dSmrg 	  struct cgraph_simd_clone *clone = clone_info;
17021debfc3dSmrg 	  if (inbranch_clause_specified && (i & 1) != 0)
17031debfc3dSmrg 	    continue;
17041debfc3dSmrg 
17051debfc3dSmrg 	  if (i != 0)
17061debfc3dSmrg 	    {
17071debfc3dSmrg 	      clone = simd_clone_struct_alloc (clone_info->nargs
17081debfc3dSmrg 					       + ((i & 1) != 0));
17091debfc3dSmrg 	      simd_clone_struct_copy (clone, clone_info);
17101debfc3dSmrg 	      /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen
17111debfc3dSmrg 		 and simd_clone_adjust_argument_types did to the first
17121debfc3dSmrg 		 clone's info.  */
17131debfc3dSmrg 	      clone->nargs -= clone_info->inbranch;
17141debfc3dSmrg 	      clone->simdlen = orig_simdlen;
17151debfc3dSmrg 	      /* And call the target hook again to get the right ISA.  */
17161debfc3dSmrg 	      targetm.simd_clone.compute_vecsize_and_simdlen (node, clone,
17171debfc3dSmrg 							      base_type,
17181debfc3dSmrg 							      i / 2);
17191debfc3dSmrg 	      if ((i & 1) != 0)
17201debfc3dSmrg 		clone->inbranch = 1;
17211debfc3dSmrg 	    }
17221debfc3dSmrg 
17231debfc3dSmrg 	  /* simd_clone_mangle might fail if such a clone has been created
17241debfc3dSmrg 	     already.  */
17251debfc3dSmrg 	  tree id = simd_clone_mangle (node, clone);
17261debfc3dSmrg 	  if (id == NULL_TREE)
1727a2dc1f3fSmrg 	    {
1728a2dc1f3fSmrg 	      if (i == 0)
1729a2dc1f3fSmrg 		clone->nargs += clone->inbranch;
17301debfc3dSmrg 	      continue;
1731a2dc1f3fSmrg 	    }
17321debfc3dSmrg 
17331debfc3dSmrg 	  /* Only when we are sure we want to create the clone actually
17341debfc3dSmrg 	     clone the function (or definitions) or create another
17351debfc3dSmrg 	     extern FUNCTION_DECL (for prototypes without definitions).  */
17361debfc3dSmrg 	  struct cgraph_node *n = simd_clone_create (node);
17371debfc3dSmrg 	  if (n == NULL)
1738a2dc1f3fSmrg 	    {
1739a2dc1f3fSmrg 	      if (i == 0)
1740a2dc1f3fSmrg 		clone->nargs += clone->inbranch;
17411debfc3dSmrg 	      continue;
1742a2dc1f3fSmrg 	    }
17431debfc3dSmrg 
17441debfc3dSmrg 	  n->simdclone = clone;
17451debfc3dSmrg 	  clone->origin = node;
17461debfc3dSmrg 	  clone->next_clone = NULL;
17471debfc3dSmrg 	  if (node->simd_clones == NULL)
17481debfc3dSmrg 	    {
17491debfc3dSmrg 	      clone->prev_clone = n;
17501debfc3dSmrg 	      node->simd_clones = n;
17511debfc3dSmrg 	    }
17521debfc3dSmrg 	  else
17531debfc3dSmrg 	    {
17541debfc3dSmrg 	      clone->prev_clone = node->simd_clones->simdclone->prev_clone;
17551debfc3dSmrg 	      clone->prev_clone->simdclone->next_clone = n;
17561debfc3dSmrg 	      node->simd_clones->simdclone->prev_clone = n;
17571debfc3dSmrg 	    }
17581debfc3dSmrg 	  symtab->change_decl_assembler_name (n->decl, id);
17591debfc3dSmrg 	  /* And finally adjust the return type, parameters and for
17601debfc3dSmrg 	     definitions also function body.  */
17611debfc3dSmrg 	  if (node->definition)
17621debfc3dSmrg 	    simd_clone_adjust (n);
17631debfc3dSmrg 	  else
17641debfc3dSmrg 	    {
1765c0a68be4Smrg 	      TREE_TYPE (n->decl)
1766c0a68be4Smrg 		= build_distinct_type_copy (TREE_TYPE (n->decl));
1767c0a68be4Smrg 	      targetm.simd_clone.adjust (n);
17681debfc3dSmrg 	      simd_clone_adjust_return_type (n);
17691debfc3dSmrg 	      simd_clone_adjust_argument_types (n);
17701debfc3dSmrg 	    }
17711debfc3dSmrg 	}
17721debfc3dSmrg     }
17731debfc3dSmrg   while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
17741debfc3dSmrg }
17751debfc3dSmrg 
17761debfc3dSmrg /* Entry point for IPA simd clone creation pass.  */
17771debfc3dSmrg 
17781debfc3dSmrg static unsigned int
ipa_omp_simd_clone(void)17791debfc3dSmrg ipa_omp_simd_clone (void)
17801debfc3dSmrg {
17811debfc3dSmrg   struct cgraph_node *node;
17821debfc3dSmrg   FOR_EACH_FUNCTION (node)
17831debfc3dSmrg     expand_simd_clones (node);
17841debfc3dSmrg   return 0;
17851debfc3dSmrg }
17861debfc3dSmrg 
17871debfc3dSmrg namespace {
17881debfc3dSmrg 
17891debfc3dSmrg const pass_data pass_data_omp_simd_clone =
17901debfc3dSmrg {
17911debfc3dSmrg   SIMPLE_IPA_PASS,		/* type */
17921debfc3dSmrg   "simdclone",			/* name */
17931debfc3dSmrg   OPTGROUP_OMP,			/* optinfo_flags */
17941debfc3dSmrg   TV_NONE,			/* tv_id */
17951debfc3dSmrg   ( PROP_ssa | PROP_cfg ),	/* properties_required */
17961debfc3dSmrg   0,				/* properties_provided */
17971debfc3dSmrg   0,				/* properties_destroyed */
17981debfc3dSmrg   0,				/* todo_flags_start */
17991debfc3dSmrg   0,				/* todo_flags_finish */
18001debfc3dSmrg };
18011debfc3dSmrg 
18021debfc3dSmrg class pass_omp_simd_clone : public simple_ipa_opt_pass
18031debfc3dSmrg {
18041debfc3dSmrg public:
pass_omp_simd_clone(gcc::context * ctxt)18051debfc3dSmrg   pass_omp_simd_clone(gcc::context *ctxt)
18061debfc3dSmrg     : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt)
18071debfc3dSmrg   {}
18081debfc3dSmrg 
18091debfc3dSmrg   /* opt_pass methods: */
18101debfc3dSmrg   virtual bool gate (function *);
execute(function *)18111debfc3dSmrg   virtual unsigned int execute (function *) { return ipa_omp_simd_clone (); }
18121debfc3dSmrg };
18131debfc3dSmrg 
18141debfc3dSmrg bool
gate(function *)18151debfc3dSmrg pass_omp_simd_clone::gate (function *)
18161debfc3dSmrg {
18171debfc3dSmrg   return targetm.simd_clone.compute_vecsize_and_simdlen != NULL;
18181debfc3dSmrg }
18191debfc3dSmrg 
18201debfc3dSmrg } // anon namespace
18211debfc3dSmrg 
18221debfc3dSmrg simple_ipa_opt_pass *
make_pass_omp_simd_clone(gcc::context * ctxt)18231debfc3dSmrg make_pass_omp_simd_clone (gcc::context *ctxt)
18241debfc3dSmrg {
18251debfc3dSmrg   return new pass_omp_simd_clone (ctxt);
18261debfc3dSmrg }
1827