xref: /dflybsd-src/contrib/gcc-8.0/gcc/omp-simd-clone.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* OMP constructs' SIMD clone supporting code.
238fd1498Szrj 
338fd1498Szrj Copyright (C) 2005-2018 Free Software Foundation, Inc.
438fd1498Szrj 
538fd1498Szrj This file is part of GCC.
638fd1498Szrj 
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj 
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj 
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3.  If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>.  */
2038fd1498Szrj 
2138fd1498Szrj #include "config.h"
2238fd1498Szrj #include "system.h"
2338fd1498Szrj #include "coretypes.h"
2438fd1498Szrj #include "backend.h"
2538fd1498Szrj #include "target.h"
2638fd1498Szrj #include "tree.h"
2738fd1498Szrj #include "gimple.h"
2838fd1498Szrj #include "cfghooks.h"
2938fd1498Szrj #include "alloc-pool.h"
3038fd1498Szrj #include "tree-pass.h"
3138fd1498Szrj #include "ssa.h"
3238fd1498Szrj #include "cgraph.h"
3338fd1498Szrj #include "pretty-print.h"
3438fd1498Szrj #include "diagnostic-core.h"
3538fd1498Szrj #include "fold-const.h"
3638fd1498Szrj #include "stor-layout.h"
3738fd1498Szrj #include "cfganal.h"
3838fd1498Szrj #include "gimplify.h"
3938fd1498Szrj #include "gimple-iterator.h"
4038fd1498Szrj #include "gimplify-me.h"
4138fd1498Szrj #include "gimple-walk.h"
4238fd1498Szrj #include "langhooks.h"
4338fd1498Szrj #include "tree-cfg.h"
4438fd1498Szrj #include "tree-into-ssa.h"
4538fd1498Szrj #include "tree-dfa.h"
4638fd1498Szrj #include "cfgloop.h"
4738fd1498Szrj #include "symbol-summary.h"
4838fd1498Szrj #include "ipa-param-manipulation.h"
4938fd1498Szrj #include "tree-eh.h"
5038fd1498Szrj #include "varasm.h"
5138fd1498Szrj #include "stringpool.h"
5238fd1498Szrj #include "attribs.h"
5338fd1498Szrj #include "omp-simd-clone.h"
5438fd1498Szrj 
5538fd1498Szrj /* Return the number of elements in vector type VECTYPE, which is associated
5638fd1498Szrj    with a SIMD clone.  At present these always have a constant length.  */
5738fd1498Szrj 
5838fd1498Szrj static unsigned HOST_WIDE_INT
simd_clone_subparts(tree vectype)5938fd1498Szrj simd_clone_subparts (tree vectype)
6038fd1498Szrj {
6138fd1498Szrj   return TYPE_VECTOR_SUBPARTS (vectype).to_constant ();
6238fd1498Szrj }
6338fd1498Szrj 
6438fd1498Szrj /* Allocate a fresh `simd_clone' and return it.  NARGS is the number
6538fd1498Szrj    of arguments to reserve space for.  */
6638fd1498Szrj 
6738fd1498Szrj static struct cgraph_simd_clone *
simd_clone_struct_alloc(int nargs)6838fd1498Szrj simd_clone_struct_alloc (int nargs)
6938fd1498Szrj {
7038fd1498Szrj   struct cgraph_simd_clone *clone_info;
7138fd1498Szrj   size_t len = (sizeof (struct cgraph_simd_clone)
7238fd1498Szrj 		+ nargs * sizeof (struct cgraph_simd_clone_arg));
7338fd1498Szrj   clone_info = (struct cgraph_simd_clone *)
7438fd1498Szrj 	       ggc_internal_cleared_alloc (len);
7538fd1498Szrj   return clone_info;
7638fd1498Szrj }
7738fd1498Szrj 
7838fd1498Szrj /* Make a copy of the `struct cgraph_simd_clone' in FROM to TO.  */
7938fd1498Szrj 
8038fd1498Szrj static inline void
simd_clone_struct_copy(struct cgraph_simd_clone * to,struct cgraph_simd_clone * from)8138fd1498Szrj simd_clone_struct_copy (struct cgraph_simd_clone *to,
8238fd1498Szrj 			struct cgraph_simd_clone *from)
8338fd1498Szrj {
8438fd1498Szrj   memcpy (to, from, (sizeof (struct cgraph_simd_clone)
8538fd1498Szrj 		     + ((from->nargs - from->inbranch)
8638fd1498Szrj 			* sizeof (struct cgraph_simd_clone_arg))));
8738fd1498Szrj }
8838fd1498Szrj 
8938fd1498Szrj /* Return vector of parameter types of function FNDECL.  This uses
9038fd1498Szrj    TYPE_ARG_TYPES if available, otherwise falls back to types of
9138fd1498Szrj    DECL_ARGUMENTS types.  */
9238fd1498Szrj 
9338fd1498Szrj static vec<tree>
simd_clone_vector_of_formal_parm_types(tree fndecl)9438fd1498Szrj simd_clone_vector_of_formal_parm_types (tree fndecl)
9538fd1498Szrj {
9638fd1498Szrj   if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
9738fd1498Szrj     return ipa_get_vector_of_formal_parm_types (TREE_TYPE (fndecl));
9838fd1498Szrj   vec<tree> args = ipa_get_vector_of_formal_parms (fndecl);
9938fd1498Szrj   unsigned int i;
10038fd1498Szrj   tree arg;
10138fd1498Szrj   FOR_EACH_VEC_ELT (args, i, arg)
10238fd1498Szrj     args[i] = TREE_TYPE (args[i]);
10338fd1498Szrj   return args;
10438fd1498Szrj }
10538fd1498Szrj 
10638fd1498Szrj /* Given a simd function in NODE, extract the simd specific
10738fd1498Szrj    information from the OMP clauses passed in CLAUSES, and return
10838fd1498Szrj    the struct cgraph_simd_clone * if it should be cloned.  *INBRANCH_SPECIFIED
10938fd1498Szrj    is set to TRUE if the `inbranch' or `notinbranch' clause specified,
11038fd1498Szrj    otherwise set to FALSE.  */
11138fd1498Szrj 
11238fd1498Szrj static struct cgraph_simd_clone *
simd_clone_clauses_extract(struct cgraph_node * node,tree clauses,bool * inbranch_specified)11338fd1498Szrj simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
11438fd1498Szrj 			    bool *inbranch_specified)
11538fd1498Szrj {
11638fd1498Szrj   vec<tree> args = simd_clone_vector_of_formal_parm_types (node->decl);
11738fd1498Szrj   tree t;
11838fd1498Szrj   int n;
11938fd1498Szrj   *inbranch_specified = false;
12038fd1498Szrj 
12138fd1498Szrj   n = args.length ();
12238fd1498Szrj   if (n > 0 && args.last () == void_type_node)
12338fd1498Szrj     n--;
12438fd1498Szrj 
12538fd1498Szrj   /* Allocate one more than needed just in case this is an in-branch
12638fd1498Szrj      clone which will require a mask argument.  */
12738fd1498Szrj   struct cgraph_simd_clone *clone_info = simd_clone_struct_alloc (n + 1);
12838fd1498Szrj   clone_info->nargs = n;
12938fd1498Szrj 
13038fd1498Szrj   if (!clauses)
13138fd1498Szrj     goto out;
13238fd1498Szrj 
13338fd1498Szrj   clauses = TREE_VALUE (clauses);
13438fd1498Szrj   if (!clauses || TREE_CODE (clauses) != OMP_CLAUSE)
13538fd1498Szrj     goto out;
13638fd1498Szrj 
13738fd1498Szrj   for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t))
13838fd1498Szrj     {
13938fd1498Szrj       switch (OMP_CLAUSE_CODE (t))
14038fd1498Szrj 	{
14138fd1498Szrj 	case OMP_CLAUSE_INBRANCH:
14238fd1498Szrj 	  clone_info->inbranch = 1;
14338fd1498Szrj 	  *inbranch_specified = true;
14438fd1498Szrj 	  break;
14538fd1498Szrj 	case OMP_CLAUSE_NOTINBRANCH:
14638fd1498Szrj 	  clone_info->inbranch = 0;
14738fd1498Szrj 	  *inbranch_specified = true;
14838fd1498Szrj 	  break;
14938fd1498Szrj 	case OMP_CLAUSE_SIMDLEN:
15038fd1498Szrj 	  clone_info->simdlen
15138fd1498Szrj 	    = TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
15238fd1498Szrj 	  break;
15338fd1498Szrj 	case OMP_CLAUSE_LINEAR:
15438fd1498Szrj 	  {
15538fd1498Szrj 	    tree decl = OMP_CLAUSE_DECL (t);
15638fd1498Szrj 	    tree step = OMP_CLAUSE_LINEAR_STEP (t);
15738fd1498Szrj 	    int argno = TREE_INT_CST_LOW (decl);
15838fd1498Szrj 	    if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (t))
15938fd1498Szrj 	      {
16038fd1498Szrj 		enum cgraph_simd_clone_arg_type arg_type;
16138fd1498Szrj 		if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
16238fd1498Szrj 		  switch (OMP_CLAUSE_LINEAR_KIND (t))
16338fd1498Szrj 		    {
16438fd1498Szrj 		    case OMP_CLAUSE_LINEAR_REF:
16538fd1498Szrj 		      arg_type
16638fd1498Szrj 			= SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP;
16738fd1498Szrj 		      break;
16838fd1498Szrj 		    case OMP_CLAUSE_LINEAR_UVAL:
16938fd1498Szrj 		      arg_type
17038fd1498Szrj 			= SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP;
17138fd1498Szrj 		      break;
17238fd1498Szrj 		    case OMP_CLAUSE_LINEAR_VAL:
17338fd1498Szrj 		    case OMP_CLAUSE_LINEAR_DEFAULT:
17438fd1498Szrj 		      arg_type
17538fd1498Szrj 			= SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP;
17638fd1498Szrj 		      break;
17738fd1498Szrj 		    default:
17838fd1498Szrj 		      gcc_unreachable ();
17938fd1498Szrj 		    }
18038fd1498Szrj 		else
18138fd1498Szrj 		  arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP;
18238fd1498Szrj 		clone_info->args[argno].arg_type = arg_type;
18338fd1498Szrj 		clone_info->args[argno].linear_step = tree_to_shwi (step);
18438fd1498Szrj 		gcc_assert (clone_info->args[argno].linear_step >= 0
18538fd1498Szrj 			    && clone_info->args[argno].linear_step < n);
18638fd1498Szrj 	      }
18738fd1498Szrj 	    else
18838fd1498Szrj 	      {
18938fd1498Szrj 		if (POINTER_TYPE_P (args[argno]))
19038fd1498Szrj 		  step = fold_convert (ssizetype, step);
19138fd1498Szrj 		if (!tree_fits_shwi_p (step))
19238fd1498Szrj 		  {
19338fd1498Szrj 		    warning_at (OMP_CLAUSE_LOCATION (t), 0,
19438fd1498Szrj 				"ignoring large linear step");
19538fd1498Szrj 		    args.release ();
19638fd1498Szrj 		    return NULL;
19738fd1498Szrj 		  }
19838fd1498Szrj 		else if (integer_zerop (step))
19938fd1498Szrj 		  {
20038fd1498Szrj 		    warning_at (OMP_CLAUSE_LOCATION (t), 0,
20138fd1498Szrj 				"ignoring zero linear step");
20238fd1498Szrj 		    args.release ();
20338fd1498Szrj 		    return NULL;
20438fd1498Szrj 		  }
20538fd1498Szrj 		else
20638fd1498Szrj 		  {
20738fd1498Szrj 		    enum cgraph_simd_clone_arg_type arg_type;
20838fd1498Szrj 		    if (TREE_CODE (args[argno]) == REFERENCE_TYPE)
20938fd1498Szrj 		      switch (OMP_CLAUSE_LINEAR_KIND (t))
21038fd1498Szrj 			{
21138fd1498Szrj 			case OMP_CLAUSE_LINEAR_REF:
21238fd1498Szrj 			  arg_type
21338fd1498Szrj 			    = SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP;
21438fd1498Szrj 			  break;
21538fd1498Szrj 			case OMP_CLAUSE_LINEAR_UVAL:
21638fd1498Szrj 			  arg_type
21738fd1498Szrj 			    = SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP;
21838fd1498Szrj 			  break;
21938fd1498Szrj 			case OMP_CLAUSE_LINEAR_VAL:
22038fd1498Szrj 			case OMP_CLAUSE_LINEAR_DEFAULT:
22138fd1498Szrj 			  arg_type
22238fd1498Szrj 			    = SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP;
22338fd1498Szrj 			  break;
22438fd1498Szrj 			default:
22538fd1498Szrj 			  gcc_unreachable ();
22638fd1498Szrj 			}
22738fd1498Szrj 		    else
22838fd1498Szrj 		      arg_type = SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP;
22938fd1498Szrj 		    clone_info->args[argno].arg_type = arg_type;
23038fd1498Szrj 		    clone_info->args[argno].linear_step = tree_to_shwi (step);
23138fd1498Szrj 		  }
23238fd1498Szrj 	      }
23338fd1498Szrj 	    break;
23438fd1498Szrj 	  }
23538fd1498Szrj 	case OMP_CLAUSE_UNIFORM:
23638fd1498Szrj 	  {
23738fd1498Szrj 	    tree decl = OMP_CLAUSE_DECL (t);
23838fd1498Szrj 	    int argno = tree_to_uhwi (decl);
23938fd1498Szrj 	    clone_info->args[argno].arg_type
24038fd1498Szrj 	      = SIMD_CLONE_ARG_TYPE_UNIFORM;
24138fd1498Szrj 	    break;
24238fd1498Szrj 	  }
24338fd1498Szrj 	case OMP_CLAUSE_ALIGNED:
24438fd1498Szrj 	  {
245*58e805e6Szrj 	    /* Ignore aligned (x) for declare simd, for the ABI we really
246*58e805e6Szrj 	       need an alignment specified.  */
247*58e805e6Szrj 	    if (OMP_CLAUSE_ALIGNED_ALIGNMENT (t) == NULL_TREE)
248*58e805e6Szrj 	      break;
24938fd1498Szrj 	    tree decl = OMP_CLAUSE_DECL (t);
25038fd1498Szrj 	    int argno = tree_to_uhwi (decl);
25138fd1498Szrj 	    clone_info->args[argno].alignment
25238fd1498Szrj 	      = TREE_INT_CST_LOW (OMP_CLAUSE_ALIGNED_ALIGNMENT (t));
25338fd1498Szrj 	    break;
25438fd1498Szrj 	  }
25538fd1498Szrj 	default:
25638fd1498Szrj 	  break;
25738fd1498Szrj 	}
25838fd1498Szrj     }
25938fd1498Szrj 
26038fd1498Szrj  out:
26138fd1498Szrj   if (TYPE_ATOMIC (TREE_TYPE (TREE_TYPE (node->decl))))
26238fd1498Szrj     {
26338fd1498Szrj       warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
26438fd1498Szrj 		  "ignoring %<#pragma omp declare simd%> on function "
26538fd1498Szrj 		  "with %<_Atomic%> qualified return type");
26638fd1498Szrj       args.release ();
26738fd1498Szrj       return NULL;
26838fd1498Szrj     }
26938fd1498Szrj 
27038fd1498Szrj   for (unsigned int argno = 0; argno < clone_info->nargs; argno++)
27138fd1498Szrj     if (TYPE_ATOMIC (args[argno])
27238fd1498Szrj 	&& clone_info->args[argno].arg_type != SIMD_CLONE_ARG_TYPE_UNIFORM)
27338fd1498Szrj       {
27438fd1498Szrj 	warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
27538fd1498Szrj 		    "ignoring %<#pragma omp declare simd%> on function "
27638fd1498Szrj 		    "with %<_Atomic%> qualified non-%<uniform%> argument");
27738fd1498Szrj 	args.release ();
27838fd1498Szrj 	return NULL;
27938fd1498Szrj       }
28038fd1498Szrj 
28138fd1498Szrj   args.release ();
28238fd1498Szrj   return clone_info;
28338fd1498Szrj }
28438fd1498Szrj 
28538fd1498Szrj /* Given a SIMD clone in NODE, calculate the characteristic data
28638fd1498Szrj    type and return the coresponding type.  The characteristic data
28738fd1498Szrj    type is computed as described in the Intel Vector ABI.  */
28838fd1498Szrj 
28938fd1498Szrj static tree
simd_clone_compute_base_data_type(struct cgraph_node * node,struct cgraph_simd_clone * clone_info)29038fd1498Szrj simd_clone_compute_base_data_type (struct cgraph_node *node,
29138fd1498Szrj 				   struct cgraph_simd_clone *clone_info)
29238fd1498Szrj {
29338fd1498Szrj   tree type = integer_type_node;
29438fd1498Szrj   tree fndecl = node->decl;
29538fd1498Szrj 
29638fd1498Szrj   /* a) For non-void function, the characteristic data type is the
29738fd1498Szrj         return type.  */
29838fd1498Szrj   if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE)
29938fd1498Szrj     type = TREE_TYPE (TREE_TYPE (fndecl));
30038fd1498Szrj 
30138fd1498Szrj   /* b) If the function has any non-uniform, non-linear parameters,
30238fd1498Szrj         then the characteristic data type is the type of the first
30338fd1498Szrj         such parameter.  */
30438fd1498Szrj   else
30538fd1498Szrj     {
30638fd1498Szrj       vec<tree> map = simd_clone_vector_of_formal_parm_types (fndecl);
30738fd1498Szrj       for (unsigned int i = 0; i < clone_info->nargs; ++i)
30838fd1498Szrj 	if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
30938fd1498Szrj 	  {
31038fd1498Szrj 	    type = map[i];
31138fd1498Szrj 	    break;
31238fd1498Szrj 	  }
31338fd1498Szrj       map.release ();
31438fd1498Szrj     }
31538fd1498Szrj 
31638fd1498Szrj   /* c) If the characteristic data type determined by a) or b) above
31738fd1498Szrj         is struct, union, or class type which is pass-by-value (except
31838fd1498Szrj         for the type that maps to the built-in complex data type), the
31938fd1498Szrj         characteristic data type is int.  */
32038fd1498Szrj   if (RECORD_OR_UNION_TYPE_P (type)
32138fd1498Szrj       && !aggregate_value_p (type, NULL)
32238fd1498Szrj       && TREE_CODE (type) != COMPLEX_TYPE)
32338fd1498Szrj     return integer_type_node;
32438fd1498Szrj 
32538fd1498Szrj   /* d) If none of the above three classes is applicable, the
32638fd1498Szrj         characteristic data type is int.  */
32738fd1498Szrj 
32838fd1498Szrj   return type;
32938fd1498Szrj 
33038fd1498Szrj   /* e) For Intel Xeon Phi native and offload compilation, if the
33138fd1498Szrj         resulting characteristic data type is 8-bit or 16-bit integer
33238fd1498Szrj         data type, the characteristic data type is int.  */
33338fd1498Szrj   /* Well, we don't handle Xeon Phi yet.  */
33438fd1498Szrj }
33538fd1498Szrj 
33638fd1498Szrj static tree
simd_clone_mangle(struct cgraph_node * node,struct cgraph_simd_clone * clone_info)33738fd1498Szrj simd_clone_mangle (struct cgraph_node *node,
33838fd1498Szrj 		   struct cgraph_simd_clone *clone_info)
33938fd1498Szrj {
34038fd1498Szrj   char vecsize_mangle = clone_info->vecsize_mangle;
34138fd1498Szrj   char mask = clone_info->inbranch ? 'M' : 'N';
34238fd1498Szrj   unsigned int simdlen = clone_info->simdlen;
34338fd1498Szrj   unsigned int n;
34438fd1498Szrj   pretty_printer pp;
34538fd1498Szrj 
34638fd1498Szrj   gcc_assert (vecsize_mangle && simdlen);
34738fd1498Szrj 
34838fd1498Szrj   pp_string (&pp, "_ZGV");
34938fd1498Szrj   pp_character (&pp, vecsize_mangle);
35038fd1498Szrj   pp_character (&pp, mask);
35138fd1498Szrj   pp_decimal_int (&pp, simdlen);
35238fd1498Szrj 
35338fd1498Szrj   for (n = 0; n < clone_info->nargs; ++n)
35438fd1498Szrj     {
35538fd1498Szrj       struct cgraph_simd_clone_arg arg = clone_info->args[n];
35638fd1498Szrj 
35738fd1498Szrj       switch (arg.arg_type)
35838fd1498Szrj 	{
35938fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_UNIFORM:
36038fd1498Szrj 	  pp_character (&pp, 'u');
36138fd1498Szrj 	  break;
36238fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
36338fd1498Szrj 	  pp_character (&pp, 'l');
36438fd1498Szrj 	  goto mangle_linear;
36538fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
36638fd1498Szrj 	  pp_character (&pp, 'R');
36738fd1498Szrj 	  goto mangle_linear;
36838fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
36938fd1498Szrj 	  pp_character (&pp, 'L');
37038fd1498Szrj 	  goto mangle_linear;
37138fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
37238fd1498Szrj 	  pp_character (&pp, 'U');
37338fd1498Szrj 	  goto mangle_linear;
37438fd1498Szrj 	mangle_linear:
37538fd1498Szrj 	  gcc_assert (arg.linear_step != 0);
37638fd1498Szrj 	  if (arg.linear_step > 1)
37738fd1498Szrj 	    pp_unsigned_wide_integer (&pp, arg.linear_step);
37838fd1498Szrj 	  else if (arg.linear_step < 0)
37938fd1498Szrj 	    {
38038fd1498Szrj 	      pp_character (&pp, 'n');
38138fd1498Szrj 	      pp_unsigned_wide_integer (&pp, (-(unsigned HOST_WIDE_INT)
38238fd1498Szrj 					      arg.linear_step));
38338fd1498Szrj 	    }
38438fd1498Szrj 	  break;
38538fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
38638fd1498Szrj 	  pp_string (&pp, "ls");
38738fd1498Szrj 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
38838fd1498Szrj 	  break;
38938fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
39038fd1498Szrj 	  pp_string (&pp, "Rs");
39138fd1498Szrj 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
39238fd1498Szrj 	  break;
39338fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
39438fd1498Szrj 	  pp_string (&pp, "Ls");
39538fd1498Szrj 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
39638fd1498Szrj 	  break;
39738fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
39838fd1498Szrj 	  pp_string (&pp, "Us");
39938fd1498Szrj 	  pp_unsigned_wide_integer (&pp, arg.linear_step);
40038fd1498Szrj 	  break;
40138fd1498Szrj 	default:
40238fd1498Szrj 	  pp_character (&pp, 'v');
40338fd1498Szrj 	}
40438fd1498Szrj       if (arg.alignment)
40538fd1498Szrj 	{
40638fd1498Szrj 	  pp_character (&pp, 'a');
40738fd1498Szrj 	  pp_decimal_int (&pp, arg.alignment);
40838fd1498Szrj 	}
40938fd1498Szrj     }
41038fd1498Szrj 
41138fd1498Szrj   pp_underscore (&pp);
41238fd1498Szrj   const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl));
41338fd1498Szrj   if (*str == '*')
41438fd1498Szrj     ++str;
41538fd1498Szrj   pp_string (&pp, str);
41638fd1498Szrj   str = pp_formatted_text (&pp);
41738fd1498Szrj 
41838fd1498Szrj   /* If there already is a SIMD clone with the same mangled name, don't
41938fd1498Szrj      add another one.  This can happen e.g. for
42038fd1498Szrj      #pragma omp declare simd
42138fd1498Szrj      #pragma omp declare simd simdlen(8)
42238fd1498Szrj      int foo (int, int);
42338fd1498Szrj      if the simdlen is assumed to be 8 for the first one, etc.  */
42438fd1498Szrj   for (struct cgraph_node *clone = node->simd_clones; clone;
42538fd1498Szrj        clone = clone->simdclone->next_clone)
42638fd1498Szrj     if (id_equal (DECL_ASSEMBLER_NAME (clone->decl), str))
42738fd1498Szrj       return NULL_TREE;
42838fd1498Szrj 
42938fd1498Szrj   return get_identifier (str);
43038fd1498Szrj }
43138fd1498Szrj 
43238fd1498Szrj /* Create a simd clone of OLD_NODE and return it.  */
43338fd1498Szrj 
43438fd1498Szrj static struct cgraph_node *
simd_clone_create(struct cgraph_node * old_node)43538fd1498Szrj simd_clone_create (struct cgraph_node *old_node)
43638fd1498Szrj {
43738fd1498Szrj   struct cgraph_node *new_node;
43838fd1498Szrj   if (old_node->definition)
43938fd1498Szrj     {
44038fd1498Szrj       if (!old_node->has_gimple_body_p ())
44138fd1498Szrj 	return NULL;
44238fd1498Szrj       old_node->get_body ();
44338fd1498Szrj       new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL,
44438fd1498Szrj 							   false, NULL, NULL,
44538fd1498Szrj 							   "simdclone");
44638fd1498Szrj     }
44738fd1498Szrj   else
44838fd1498Szrj     {
44938fd1498Szrj       tree old_decl = old_node->decl;
45038fd1498Szrj       tree new_decl = copy_node (old_node->decl);
45138fd1498Szrj       DECL_NAME (new_decl) = clone_function_name (old_decl, "simdclone");
45238fd1498Szrj       SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
45338fd1498Szrj       SET_DECL_RTL (new_decl, NULL);
45438fd1498Szrj       DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
45538fd1498Szrj       DECL_STATIC_DESTRUCTOR (new_decl) = 0;
45638fd1498Szrj       new_node = old_node->create_version_clone (new_decl, vNULL, NULL);
45738fd1498Szrj       if (old_node->in_other_partition)
45838fd1498Szrj 	new_node->in_other_partition = 1;
45938fd1498Szrj     }
46038fd1498Szrj   if (new_node == NULL)
46138fd1498Szrj     return new_node;
46238fd1498Szrj 
46338fd1498Szrj   DECL_BUILT_IN_CLASS (new_node->decl) = NOT_BUILT_IN;
46438fd1498Szrj   DECL_FUNCTION_CODE (new_node->decl) = (enum built_in_function) 0;
46538fd1498Szrj   TREE_PUBLIC (new_node->decl) = TREE_PUBLIC (old_node->decl);
46638fd1498Szrj   DECL_COMDAT (new_node->decl) = DECL_COMDAT (old_node->decl);
46738fd1498Szrj   DECL_WEAK (new_node->decl) = DECL_WEAK (old_node->decl);
46838fd1498Szrj   DECL_EXTERNAL (new_node->decl) = DECL_EXTERNAL (old_node->decl);
46938fd1498Szrj   DECL_VISIBILITY_SPECIFIED (new_node->decl)
47038fd1498Szrj     = DECL_VISIBILITY_SPECIFIED (old_node->decl);
47138fd1498Szrj   DECL_VISIBILITY (new_node->decl) = DECL_VISIBILITY (old_node->decl);
47238fd1498Szrj   DECL_DLLIMPORT_P (new_node->decl) = DECL_DLLIMPORT_P (old_node->decl);
47338fd1498Szrj   if (DECL_ONE_ONLY (old_node->decl))
47438fd1498Szrj     make_decl_one_only (new_node->decl, DECL_ASSEMBLER_NAME (new_node->decl));
47538fd1498Szrj 
47638fd1498Szrj   /* The method cgraph_version_clone_with_body () will force the new
47738fd1498Szrj      symbol local.  Undo this, and inherit external visibility from
47838fd1498Szrj      the old node.  */
47938fd1498Szrj   new_node->local.local = old_node->local.local;
48038fd1498Szrj   new_node->externally_visible = old_node->externally_visible;
48138fd1498Szrj 
48238fd1498Szrj   return new_node;
48338fd1498Szrj }
48438fd1498Szrj 
48538fd1498Szrj /* Adjust the return type of the given function to its appropriate
48638fd1498Szrj    vector counterpart.  Returns a simd array to be used throughout the
48738fd1498Szrj    function as a return value.  */
48838fd1498Szrj 
48938fd1498Szrj static tree
simd_clone_adjust_return_type(struct cgraph_node * node)49038fd1498Szrj simd_clone_adjust_return_type (struct cgraph_node *node)
49138fd1498Szrj {
49238fd1498Szrj   tree fndecl = node->decl;
49338fd1498Szrj   tree orig_rettype = TREE_TYPE (TREE_TYPE (fndecl));
49438fd1498Szrj   unsigned int veclen;
49538fd1498Szrj   tree t;
49638fd1498Szrj 
49738fd1498Szrj   /* Adjust the function return type.  */
49838fd1498Szrj   if (orig_rettype == void_type_node)
49938fd1498Szrj     return NULL_TREE;
50038fd1498Szrj   TREE_TYPE (fndecl) = build_distinct_type_copy (TREE_TYPE (fndecl));
50138fd1498Szrj   t = TREE_TYPE (TREE_TYPE (fndecl));
50238fd1498Szrj   if (INTEGRAL_TYPE_P (t) || POINTER_TYPE_P (t))
50338fd1498Szrj     veclen = node->simdclone->vecsize_int;
50438fd1498Szrj   else
50538fd1498Szrj     veclen = node->simdclone->vecsize_float;
50638fd1498Szrj   veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (t));
50738fd1498Szrj   if (veclen > node->simdclone->simdlen)
50838fd1498Szrj     veclen = node->simdclone->simdlen;
50938fd1498Szrj   if (POINTER_TYPE_P (t))
51038fd1498Szrj     t = pointer_sized_int_node;
51138fd1498Szrj   if (veclen == node->simdclone->simdlen)
51238fd1498Szrj     t = build_vector_type (t, node->simdclone->simdlen);
51338fd1498Szrj   else
51438fd1498Szrj     {
51538fd1498Szrj       t = build_vector_type (t, veclen);
51638fd1498Szrj       t = build_array_type_nelts (t, node->simdclone->simdlen / veclen);
51738fd1498Szrj     }
51838fd1498Szrj   TREE_TYPE (TREE_TYPE (fndecl)) = t;
51938fd1498Szrj   if (!node->definition)
52038fd1498Szrj     return NULL_TREE;
52138fd1498Szrj 
52238fd1498Szrj   t = DECL_RESULT (fndecl);
52338fd1498Szrj   /* Adjust the DECL_RESULT.  */
52438fd1498Szrj   gcc_assert (TREE_TYPE (t) != void_type_node);
52538fd1498Szrj   TREE_TYPE (t) = TREE_TYPE (TREE_TYPE (fndecl));
52638fd1498Szrj   relayout_decl (t);
52738fd1498Szrj 
52838fd1498Szrj   tree atype = build_array_type_nelts (orig_rettype,
52938fd1498Szrj 				       node->simdclone->simdlen);
53038fd1498Szrj   if (veclen != node->simdclone->simdlen)
53138fd1498Szrj     return build1 (VIEW_CONVERT_EXPR, atype, t);
53238fd1498Szrj 
53338fd1498Szrj   /* Set up a SIMD array to use as the return value.  */
53438fd1498Szrj   tree retval = create_tmp_var_raw (atype, "retval");
53538fd1498Szrj   gimple_add_tmp_var (retval);
53638fd1498Szrj   return retval;
53738fd1498Szrj }
53838fd1498Szrj 
53938fd1498Szrj /* Each vector argument has a corresponding array to be used locally
54038fd1498Szrj    as part of the eventual loop.  Create such temporary array and
54138fd1498Szrj    return it.
54238fd1498Szrj 
54338fd1498Szrj    PREFIX is the prefix to be used for the temporary.
54438fd1498Szrj 
54538fd1498Szrj    TYPE is the inner element type.
54638fd1498Szrj 
54738fd1498Szrj    SIMDLEN is the number of elements.  */
54838fd1498Szrj 
54938fd1498Szrj static tree
create_tmp_simd_array(const char * prefix,tree type,int simdlen)55038fd1498Szrj create_tmp_simd_array (const char *prefix, tree type, int simdlen)
55138fd1498Szrj {
55238fd1498Szrj   tree atype = build_array_type_nelts (type, simdlen);
55338fd1498Szrj   tree avar = create_tmp_var_raw (atype, prefix);
55438fd1498Szrj   gimple_add_tmp_var (avar);
55538fd1498Szrj   return avar;
55638fd1498Szrj }
55738fd1498Szrj 
55838fd1498Szrj /* Modify the function argument types to their corresponding vector
55938fd1498Szrj    counterparts if appropriate.  Also, create one array for each simd
56038fd1498Szrj    argument to be used locally when using the function arguments as
56138fd1498Szrj    part of the loop.
56238fd1498Szrj 
56338fd1498Szrj    NODE is the function whose arguments are to be adjusted.
56438fd1498Szrj 
56538fd1498Szrj    Returns an adjustment vector that will be filled describing how the
56638fd1498Szrj    argument types will be adjusted.  */
56738fd1498Szrj 
56838fd1498Szrj static ipa_parm_adjustment_vec
simd_clone_adjust_argument_types(struct cgraph_node * node)56938fd1498Szrj simd_clone_adjust_argument_types (struct cgraph_node *node)
57038fd1498Szrj {
57138fd1498Szrj   vec<tree> args;
57238fd1498Szrj   ipa_parm_adjustment_vec adjustments;
57338fd1498Szrj 
57438fd1498Szrj   if (node->definition)
57538fd1498Szrj     args = ipa_get_vector_of_formal_parms (node->decl);
57638fd1498Szrj   else
57738fd1498Szrj     args = simd_clone_vector_of_formal_parm_types (node->decl);
57838fd1498Szrj   adjustments.create (args.length ());
57938fd1498Szrj   unsigned i, j, veclen;
58038fd1498Szrj   struct ipa_parm_adjustment adj;
58138fd1498Szrj   struct cgraph_simd_clone *sc = node->simdclone;
58238fd1498Szrj 
58338fd1498Szrj   for (i = 0; i < sc->nargs; ++i)
58438fd1498Szrj     {
58538fd1498Szrj       memset (&adj, 0, sizeof (adj));
58638fd1498Szrj       tree parm = args[i];
58738fd1498Szrj       tree parm_type = node->definition ? TREE_TYPE (parm) : parm;
58838fd1498Szrj       adj.base_index = i;
58938fd1498Szrj       adj.base = parm;
59038fd1498Szrj 
59138fd1498Szrj       sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
59238fd1498Szrj       sc->args[i].orig_type = parm_type;
59338fd1498Szrj 
59438fd1498Szrj       switch (sc->args[i].arg_type)
59538fd1498Szrj 	{
59638fd1498Szrj 	default:
59738fd1498Szrj 	  /* No adjustment necessary for scalar arguments.  */
59838fd1498Szrj 	  adj.op = IPA_PARM_OP_COPY;
59938fd1498Szrj 	  break;
60038fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
60138fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
60238fd1498Szrj 	  if (node->definition)
60338fd1498Szrj 	    sc->args[i].simd_array
60438fd1498Szrj 	      = create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
60538fd1498Szrj 				       TREE_TYPE (parm_type),
60638fd1498Szrj 				       sc->simdlen);
60738fd1498Szrj 	  adj.op = IPA_PARM_OP_COPY;
60838fd1498Szrj 	  break;
60938fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
61038fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
61138fd1498Szrj 	case SIMD_CLONE_ARG_TYPE_VECTOR:
61238fd1498Szrj 	  if (INTEGRAL_TYPE_P (parm_type) || POINTER_TYPE_P (parm_type))
61338fd1498Szrj 	    veclen = sc->vecsize_int;
61438fd1498Szrj 	  else
61538fd1498Szrj 	    veclen = sc->vecsize_float;
61638fd1498Szrj 	  veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type));
61738fd1498Szrj 	  if (veclen > sc->simdlen)
61838fd1498Szrj 	    veclen = sc->simdlen;
61938fd1498Szrj 	  adj.arg_prefix = "simd";
62038fd1498Szrj 	  if (POINTER_TYPE_P (parm_type))
62138fd1498Szrj 	    adj.type = build_vector_type (pointer_sized_int_node, veclen);
62238fd1498Szrj 	  else
62338fd1498Szrj 	    adj.type = build_vector_type (parm_type, veclen);
62438fd1498Szrj 	  sc->args[i].vector_type = adj.type;
62538fd1498Szrj 	  for (j = veclen; j < sc->simdlen; j += veclen)
62638fd1498Szrj 	    {
62738fd1498Szrj 	      adjustments.safe_push (adj);
62838fd1498Szrj 	      if (j == veclen)
62938fd1498Szrj 		{
63038fd1498Szrj 		  memset (&adj, 0, sizeof (adj));
63138fd1498Szrj 		  adj.op = IPA_PARM_OP_NEW;
63238fd1498Szrj 		  adj.arg_prefix = "simd";
63338fd1498Szrj 		  adj.base_index = i;
63438fd1498Szrj 		  adj.type = sc->args[i].vector_type;
63538fd1498Szrj 		}
63638fd1498Szrj 	    }
63738fd1498Szrj 
63838fd1498Szrj 	  if (node->definition)
63938fd1498Szrj 	    sc->args[i].simd_array
64038fd1498Szrj 	      = create_tmp_simd_array (DECL_NAME (parm)
64138fd1498Szrj 				       ? IDENTIFIER_POINTER (DECL_NAME (parm))
64238fd1498Szrj 				       : NULL, parm_type, sc->simdlen);
64338fd1498Szrj 	}
64438fd1498Szrj       adjustments.safe_push (adj);
64538fd1498Szrj     }
64638fd1498Szrj 
64738fd1498Szrj   if (sc->inbranch)
64838fd1498Szrj     {
64938fd1498Szrj       tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
65038fd1498Szrj 
65138fd1498Szrj       memset (&adj, 0, sizeof (adj));
65238fd1498Szrj       adj.op = IPA_PARM_OP_NEW;
65338fd1498Szrj       adj.arg_prefix = "mask";
65438fd1498Szrj 
65538fd1498Szrj       adj.base_index = i;
65638fd1498Szrj       if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
65738fd1498Szrj 	veclen = sc->vecsize_int;
65838fd1498Szrj       else
65938fd1498Szrj 	veclen = sc->vecsize_float;
66038fd1498Szrj       veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type));
66138fd1498Szrj       if (veclen > sc->simdlen)
66238fd1498Szrj 	veclen = sc->simdlen;
66338fd1498Szrj       if (sc->mask_mode != VOIDmode)
66438fd1498Szrj 	adj.type
66538fd1498Szrj 	  = lang_hooks.types.type_for_mode (sc->mask_mode, 1);
66638fd1498Szrj       else if (POINTER_TYPE_P (base_type))
66738fd1498Szrj 	adj.type = build_vector_type (pointer_sized_int_node, veclen);
66838fd1498Szrj       else
66938fd1498Szrj 	adj.type = build_vector_type (base_type, veclen);
67038fd1498Szrj       adjustments.safe_push (adj);
67138fd1498Szrj 
67238fd1498Szrj       for (j = veclen; j < sc->simdlen; j += veclen)
67338fd1498Szrj 	adjustments.safe_push (adj);
67438fd1498Szrj 
67538fd1498Szrj       /* We have previously allocated one extra entry for the mask.  Use
67638fd1498Szrj 	 it and fill it.  */
67738fd1498Szrj       sc->nargs++;
67838fd1498Szrj       if (sc->mask_mode != VOIDmode)
67938fd1498Szrj 	base_type = boolean_type_node;
68038fd1498Szrj       if (node->definition)
68138fd1498Szrj 	{
68238fd1498Szrj 	  sc->args[i].orig_arg
68338fd1498Szrj 	    = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL, base_type);
68438fd1498Szrj 	  if (sc->mask_mode == VOIDmode)
68538fd1498Szrj 	    sc->args[i].simd_array
68638fd1498Szrj 	      = create_tmp_simd_array ("mask", base_type, sc->simdlen);
68738fd1498Szrj 	  else if (veclen < sc->simdlen)
68838fd1498Szrj 	    sc->args[i].simd_array
68938fd1498Szrj 	      = create_tmp_simd_array ("mask", adj.type, sc->simdlen / veclen);
69038fd1498Szrj 	  else
69138fd1498Szrj 	    sc->args[i].simd_array = NULL_TREE;
69238fd1498Szrj 	}
69338fd1498Szrj       sc->args[i].orig_type = base_type;
69438fd1498Szrj       sc->args[i].arg_type = SIMD_CLONE_ARG_TYPE_MASK;
69538fd1498Szrj     }
69638fd1498Szrj 
69738fd1498Szrj   if (node->definition)
69838fd1498Szrj     ipa_modify_formal_parameters (node->decl, adjustments);
69938fd1498Szrj   else
70038fd1498Szrj     {
70138fd1498Szrj       tree new_arg_types = NULL_TREE, new_reversed;
70238fd1498Szrj       bool last_parm_void = false;
70338fd1498Szrj       if (args.length () > 0 && args.last () == void_type_node)
70438fd1498Szrj 	last_parm_void = true;
70538fd1498Szrj 
70638fd1498Szrj       gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
70738fd1498Szrj       j = adjustments.length ();
70838fd1498Szrj       for (i = 0; i < j; i++)
70938fd1498Szrj 	{
71038fd1498Szrj 	  struct ipa_parm_adjustment *adj = &adjustments[i];
71138fd1498Szrj 	  tree ptype;
71238fd1498Szrj 	  if (adj->op == IPA_PARM_OP_COPY)
71338fd1498Szrj 	    ptype = args[adj->base_index];
71438fd1498Szrj 	  else
71538fd1498Szrj 	    ptype = adj->type;
71638fd1498Szrj 	  new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types);
71738fd1498Szrj 	}
71838fd1498Szrj       new_reversed = nreverse (new_arg_types);
71938fd1498Szrj       if (last_parm_void)
72038fd1498Szrj 	{
72138fd1498Szrj 	  if (new_reversed)
72238fd1498Szrj 	    TREE_CHAIN (new_arg_types) = void_list_node;
72338fd1498Szrj 	  else
72438fd1498Szrj 	    new_reversed = void_list_node;
72538fd1498Szrj 	}
72638fd1498Szrj 
72738fd1498Szrj       tree new_type = build_distinct_type_copy (TREE_TYPE (node->decl));
72838fd1498Szrj       TYPE_ARG_TYPES (new_type) = new_reversed;
72938fd1498Szrj       TREE_TYPE (node->decl) = new_type;
73038fd1498Szrj 
73138fd1498Szrj       adjustments.release ();
73238fd1498Szrj     }
73338fd1498Szrj   args.release ();
73438fd1498Szrj   return adjustments;
73538fd1498Szrj }
73638fd1498Szrj 
73738fd1498Szrj /* Initialize and copy the function arguments in NODE to their
73838fd1498Szrj    corresponding local simd arrays.  Returns a fresh gimple_seq with
73938fd1498Szrj    the instruction sequence generated.  */
74038fd1498Szrj 
74138fd1498Szrj static gimple_seq
simd_clone_init_simd_arrays(struct cgraph_node * node,ipa_parm_adjustment_vec adjustments)74238fd1498Szrj simd_clone_init_simd_arrays (struct cgraph_node *node,
74338fd1498Szrj 			     ipa_parm_adjustment_vec adjustments)
74438fd1498Szrj {
74538fd1498Szrj   gimple_seq seq = NULL;
74638fd1498Szrj   unsigned i = 0, j = 0, k;
74738fd1498Szrj 
74838fd1498Szrj   for (tree arg = DECL_ARGUMENTS (node->decl);
74938fd1498Szrj        arg;
75038fd1498Szrj        arg = DECL_CHAIN (arg), i++, j++)
75138fd1498Szrj     {
75238fd1498Szrj       if (adjustments[j].op == IPA_PARM_OP_COPY
75338fd1498Szrj 	  || POINTER_TYPE_P (TREE_TYPE (arg)))
75438fd1498Szrj 	continue;
75538fd1498Szrj 
75638fd1498Szrj       node->simdclone->args[i].vector_arg = arg;
75738fd1498Szrj 
75838fd1498Szrj       tree array = node->simdclone->args[i].simd_array;
75938fd1498Szrj       if (node->simdclone->mask_mode != VOIDmode
76038fd1498Szrj 	  && node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_MASK)
76138fd1498Szrj 	{
76238fd1498Szrj 	  if (array == NULL_TREE)
76338fd1498Szrj 	    continue;
76438fd1498Szrj 	  unsigned int l
76538fd1498Szrj 	    = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (array))));
76638fd1498Szrj 	  for (k = 0; k <= l; k++)
76738fd1498Szrj 	    {
76838fd1498Szrj 	      if (k)
76938fd1498Szrj 		{
77038fd1498Szrj 		  arg = DECL_CHAIN (arg);
77138fd1498Szrj 		  j++;
77238fd1498Szrj 		}
77338fd1498Szrj 	      tree t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
77438fd1498Szrj 			       array, size_int (k), NULL, NULL);
77538fd1498Szrj 	      t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
77638fd1498Szrj 	      gimplify_and_add (t, &seq);
77738fd1498Szrj 	    }
77838fd1498Szrj 	  continue;
77938fd1498Szrj 	}
78038fd1498Szrj       if (simd_clone_subparts (TREE_TYPE (arg)) == node->simdclone->simdlen)
78138fd1498Szrj 	{
78238fd1498Szrj 	  tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
78338fd1498Szrj 	  tree ptr = build_fold_addr_expr (array);
78438fd1498Szrj 	  tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
78538fd1498Szrj 			   build_int_cst (ptype, 0));
78638fd1498Szrj 	  t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
78738fd1498Szrj 	  gimplify_and_add (t, &seq);
78838fd1498Szrj 	}
78938fd1498Szrj       else
79038fd1498Szrj 	{
79138fd1498Szrj 	  unsigned int simdlen = simd_clone_subparts (TREE_TYPE (arg));
79238fd1498Szrj 	  tree ptype = build_pointer_type (TREE_TYPE (TREE_TYPE (array)));
79338fd1498Szrj 	  for (k = 0; k < node->simdclone->simdlen; k += simdlen)
79438fd1498Szrj 	    {
79538fd1498Szrj 	      tree ptr = build_fold_addr_expr (array);
79638fd1498Szrj 	      int elemsize;
79738fd1498Szrj 	      if (k)
79838fd1498Szrj 		{
79938fd1498Szrj 		  arg = DECL_CHAIN (arg);
80038fd1498Szrj 		  j++;
80138fd1498Szrj 		}
80238fd1498Szrj 	      tree elemtype = TREE_TYPE (TREE_TYPE (arg));
80338fd1498Szrj 	      elemsize = GET_MODE_SIZE (SCALAR_TYPE_MODE (elemtype));
80438fd1498Szrj 	      tree t = build2 (MEM_REF, TREE_TYPE (arg), ptr,
80538fd1498Szrj 			       build_int_cst (ptype, k * elemsize));
80638fd1498Szrj 	      t = build2 (MODIFY_EXPR, TREE_TYPE (t), t, arg);
80738fd1498Szrj 	      gimplify_and_add (t, &seq);
80838fd1498Szrj 	    }
80938fd1498Szrj 	}
81038fd1498Szrj     }
81138fd1498Szrj   return seq;
81238fd1498Szrj }
81338fd1498Szrj 
81438fd1498Szrj /* Callback info for ipa_simd_modify_stmt_ops below.  */
81538fd1498Szrj 
81638fd1498Szrj struct modify_stmt_info {
81738fd1498Szrj   ipa_parm_adjustment_vec adjustments;
81838fd1498Szrj   gimple *stmt;
81938fd1498Szrj   /* True if the parent statement was modified by
82038fd1498Szrj      ipa_simd_modify_stmt_ops.  */
82138fd1498Szrj   bool modified;
82238fd1498Szrj };
82338fd1498Szrj 
82438fd1498Szrj /* Callback for walk_gimple_op.
82538fd1498Szrj 
82638fd1498Szrj    Adjust operands from a given statement as specified in the
82738fd1498Szrj    adjustments vector in the callback data.  */
82838fd1498Szrj 
82938fd1498Szrj static tree
ipa_simd_modify_stmt_ops(tree * tp,int * walk_subtrees,void * data)83038fd1498Szrj ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
83138fd1498Szrj {
83238fd1498Szrj   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
83338fd1498Szrj   struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
83438fd1498Szrj   tree *orig_tp = tp;
83538fd1498Szrj   if (TREE_CODE (*tp) == ADDR_EXPR)
83638fd1498Szrj     tp = &TREE_OPERAND (*tp, 0);
83738fd1498Szrj   struct ipa_parm_adjustment *cand = NULL;
83838fd1498Szrj   if (TREE_CODE (*tp) == PARM_DECL)
83938fd1498Szrj     cand = ipa_get_adjustment_candidate (&tp, NULL, info->adjustments, true);
84038fd1498Szrj   else
84138fd1498Szrj     {
84238fd1498Szrj       if (TYPE_P (*tp))
84338fd1498Szrj 	*walk_subtrees = 0;
84438fd1498Szrj     }
84538fd1498Szrj 
84638fd1498Szrj   tree repl = NULL_TREE;
84738fd1498Szrj   if (cand)
84838fd1498Szrj     repl = unshare_expr (cand->new_decl);
84938fd1498Szrj   else
85038fd1498Szrj     {
85138fd1498Szrj       if (tp != orig_tp)
85238fd1498Szrj 	{
85338fd1498Szrj 	  *walk_subtrees = 0;
85438fd1498Szrj 	  bool modified = info->modified;
85538fd1498Szrj 	  info->modified = false;
85638fd1498Szrj 	  walk_tree (tp, ipa_simd_modify_stmt_ops, wi, wi->pset);
85738fd1498Szrj 	  if (!info->modified)
85838fd1498Szrj 	    {
85938fd1498Szrj 	      info->modified = modified;
86038fd1498Szrj 	      return NULL_TREE;
86138fd1498Szrj 	    }
86238fd1498Szrj 	  info->modified = modified;
86338fd1498Szrj 	  repl = *tp;
86438fd1498Szrj 	}
86538fd1498Szrj       else
86638fd1498Szrj 	return NULL_TREE;
86738fd1498Szrj     }
86838fd1498Szrj 
86938fd1498Szrj   if (tp != orig_tp)
87038fd1498Szrj     {
87138fd1498Szrj       repl = build_fold_addr_expr (repl);
87238fd1498Szrj       gimple *stmt;
87338fd1498Szrj       if (is_gimple_debug (info->stmt))
87438fd1498Szrj 	{
87538fd1498Szrj 	  tree vexpr = make_node (DEBUG_EXPR_DECL);
87638fd1498Szrj 	  stmt = gimple_build_debug_source_bind (vexpr, repl, NULL);
87738fd1498Szrj 	  DECL_ARTIFICIAL (vexpr) = 1;
87838fd1498Szrj 	  TREE_TYPE (vexpr) = TREE_TYPE (repl);
87938fd1498Szrj 	  SET_DECL_MODE (vexpr, TYPE_MODE (TREE_TYPE (repl)));
88038fd1498Szrj 	  repl = vexpr;
88138fd1498Szrj 	}
88238fd1498Szrj       else
88338fd1498Szrj 	{
88438fd1498Szrj 	  stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
88538fd1498Szrj 	  repl = gimple_assign_lhs (stmt);
88638fd1498Szrj 	}
88738fd1498Szrj       gimple_stmt_iterator gsi = gsi_for_stmt (info->stmt);
88838fd1498Szrj       gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
88938fd1498Szrj       *orig_tp = repl;
89038fd1498Szrj     }
89138fd1498Szrj   else if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
89238fd1498Szrj     {
89338fd1498Szrj       tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
89438fd1498Szrj       *tp = vce;
89538fd1498Szrj     }
89638fd1498Szrj   else
89738fd1498Szrj     *tp = repl;
89838fd1498Szrj 
89938fd1498Szrj   info->modified = true;
90038fd1498Szrj   return NULL_TREE;
90138fd1498Szrj }
90238fd1498Szrj 
90338fd1498Szrj /* Traverse the function body and perform all modifications as
90438fd1498Szrj    described in ADJUSTMENTS.  At function return, ADJUSTMENTS will be
90538fd1498Szrj    modified such that the replacement/reduction value will now be an
90638fd1498Szrj    offset into the corresponding simd_array.
90738fd1498Szrj 
90838fd1498Szrj    This function will replace all function argument uses with their
90938fd1498Szrj    corresponding simd array elements, and ajust the return values
91038fd1498Szrj    accordingly.  */
91138fd1498Szrj 
91238fd1498Szrj static void
ipa_simd_modify_function_body(struct cgraph_node * node,ipa_parm_adjustment_vec adjustments,tree retval_array,tree iter)91338fd1498Szrj ipa_simd_modify_function_body (struct cgraph_node *node,
91438fd1498Szrj 			       ipa_parm_adjustment_vec adjustments,
91538fd1498Szrj 			       tree retval_array, tree iter)
91638fd1498Szrj {
91738fd1498Szrj   basic_block bb;
91838fd1498Szrj   unsigned int i, j, l;
91938fd1498Szrj 
92038fd1498Szrj   /* Re-use the adjustments array, but this time use it to replace
92138fd1498Szrj      every function argument use to an offset into the corresponding
92238fd1498Szrj      simd_array.  */
92338fd1498Szrj   for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
92438fd1498Szrj     {
92538fd1498Szrj       if (!node->simdclone->args[i].vector_arg)
92638fd1498Szrj 	continue;
92738fd1498Szrj 
92838fd1498Szrj       tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
92938fd1498Szrj       tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
93038fd1498Szrj       adjustments[j].new_decl
93138fd1498Szrj 	= build4 (ARRAY_REF,
93238fd1498Szrj 		  basetype,
93338fd1498Szrj 		  node->simdclone->args[i].simd_array,
93438fd1498Szrj 		  iter,
93538fd1498Szrj 		  NULL_TREE, NULL_TREE);
93638fd1498Szrj       if (adjustments[j].op == IPA_PARM_OP_NONE
93738fd1498Szrj 	  && simd_clone_subparts (vectype) < node->simdclone->simdlen)
93838fd1498Szrj 	j += node->simdclone->simdlen / simd_clone_subparts (vectype) - 1;
93938fd1498Szrj     }
94038fd1498Szrj 
94138fd1498Szrj   l = adjustments.length ();
94238fd1498Szrj   tree name;
94338fd1498Szrj 
94438fd1498Szrj   FOR_EACH_SSA_NAME (i, name, cfun)
94538fd1498Szrj     {
94638fd1498Szrj       if (SSA_NAME_VAR (name)
94738fd1498Szrj 	  && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL)
94838fd1498Szrj 	{
94938fd1498Szrj 	  for (j = 0; j < l; j++)
95038fd1498Szrj 	    if (SSA_NAME_VAR (name) == adjustments[j].base
95138fd1498Szrj 		&& adjustments[j].new_decl)
95238fd1498Szrj 	      {
95338fd1498Szrj 		tree base_var;
95438fd1498Szrj 		if (adjustments[j].new_ssa_base == NULL_TREE)
95538fd1498Szrj 		  {
95638fd1498Szrj 		    base_var
95738fd1498Szrj 		      = copy_var_decl (adjustments[j].base,
95838fd1498Szrj 				       DECL_NAME (adjustments[j].base),
95938fd1498Szrj 				       TREE_TYPE (adjustments[j].base));
96038fd1498Szrj 		    adjustments[j].new_ssa_base = base_var;
96138fd1498Szrj 		  }
96238fd1498Szrj 		else
96338fd1498Szrj 		  base_var = adjustments[j].new_ssa_base;
96438fd1498Szrj 		if (SSA_NAME_IS_DEFAULT_DEF (name))
96538fd1498Szrj 		  {
96638fd1498Szrj 		    bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
96738fd1498Szrj 		    gimple_stmt_iterator gsi = gsi_after_labels (bb);
96838fd1498Szrj 		    tree new_decl = unshare_expr (adjustments[j].new_decl);
96938fd1498Szrj 		    set_ssa_default_def (cfun, adjustments[j].base, NULL_TREE);
97038fd1498Szrj 		    SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
97138fd1498Szrj 		    SSA_NAME_IS_DEFAULT_DEF (name) = 0;
97238fd1498Szrj 		    gimple *stmt = gimple_build_assign (name, new_decl);
97338fd1498Szrj 		    gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
97438fd1498Szrj 		  }
97538fd1498Szrj 		else
97638fd1498Szrj 		  SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
97738fd1498Szrj 	      }
97838fd1498Szrj 	}
97938fd1498Szrj     }
98038fd1498Szrj 
98138fd1498Szrj   struct modify_stmt_info info;
98238fd1498Szrj   info.adjustments = adjustments;
98338fd1498Szrj 
98438fd1498Szrj   FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
98538fd1498Szrj     {
98638fd1498Szrj       gimple_stmt_iterator gsi;
98738fd1498Szrj 
98838fd1498Szrj       gsi = gsi_start_bb (bb);
98938fd1498Szrj       while (!gsi_end_p (gsi))
99038fd1498Szrj 	{
99138fd1498Szrj 	  gimple *stmt = gsi_stmt (gsi);
99238fd1498Szrj 	  info.stmt = stmt;
99338fd1498Szrj 	  struct walk_stmt_info wi;
99438fd1498Szrj 
99538fd1498Szrj 	  memset (&wi, 0, sizeof (wi));
99638fd1498Szrj 	  info.modified = false;
99738fd1498Szrj 	  wi.info = &info;
99838fd1498Szrj 	  walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
99938fd1498Szrj 
100038fd1498Szrj 	  if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
100138fd1498Szrj 	    {
100238fd1498Szrj 	      tree retval = gimple_return_retval (return_stmt);
1003*58e805e6Szrj 	      edge e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
1004*58e805e6Szrj 	      e->flags |= EDGE_FALLTHRU;
100538fd1498Szrj 	      if (!retval)
100638fd1498Szrj 		{
100738fd1498Szrj 		  gsi_remove (&gsi, true);
100838fd1498Szrj 		  continue;
100938fd1498Szrj 		}
101038fd1498Szrj 
101138fd1498Szrj 	      /* Replace `return foo' with `retval_array[iter] = foo'.  */
101238fd1498Szrj 	      tree ref = build4 (ARRAY_REF, TREE_TYPE (retval),
101338fd1498Szrj 				 retval_array, iter, NULL, NULL);
101438fd1498Szrj 	      stmt = gimple_build_assign (ref, retval);
101538fd1498Szrj 	      gsi_replace (&gsi, stmt, true);
101638fd1498Szrj 	      info.modified = true;
101738fd1498Szrj 	    }
101838fd1498Szrj 
101938fd1498Szrj 	  if (info.modified)
102038fd1498Szrj 	    {
102138fd1498Szrj 	      update_stmt (stmt);
1022*58e805e6Szrj 	      /* If the above changed the var of a debug bind into something
1023*58e805e6Szrj 		 different, remove the debug stmt.  We could also for all the
1024*58e805e6Szrj 		 replaced parameters add VAR_DECLs for debug info purposes,
1025*58e805e6Szrj 		 add debug stmts for those to be the simd array accesses and
1026*58e805e6Szrj 		 replace debug stmt var operand with that var.  Debugging of
1027*58e805e6Szrj 		 vectorized loops doesn't work too well, so don't bother for
1028*58e805e6Szrj 		 now.  */
1029*58e805e6Szrj 	      if ((gimple_debug_bind_p (stmt)
1030*58e805e6Szrj 		   && !DECL_P (gimple_debug_bind_get_var (stmt)))
1031*58e805e6Szrj 		  || (gimple_debug_source_bind_p (stmt)
1032*58e805e6Szrj 		      && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
1033*58e805e6Szrj 		{
1034*58e805e6Szrj 		  gsi_remove (&gsi, true);
1035*58e805e6Szrj 		  continue;
1036*58e805e6Szrj 		}
103738fd1498Szrj 	      if (maybe_clean_eh_stmt (stmt))
103838fd1498Szrj 		gimple_purge_dead_eh_edges (gimple_bb (stmt));
103938fd1498Szrj 	    }
104038fd1498Szrj 	  gsi_next (&gsi);
104138fd1498Szrj 	}
104238fd1498Szrj     }
104338fd1498Szrj }
104438fd1498Szrj 
104538fd1498Szrj /* Helper function of simd_clone_adjust, return linear step addend
104638fd1498Szrj    of Ith argument.  */
104738fd1498Szrj 
104838fd1498Szrj static tree
simd_clone_linear_addend(struct cgraph_node * node,unsigned int i,tree addtype,basic_block entry_bb)104938fd1498Szrj simd_clone_linear_addend (struct cgraph_node *node, unsigned int i,
105038fd1498Szrj 			  tree addtype, basic_block entry_bb)
105138fd1498Szrj {
105238fd1498Szrj   tree ptype = NULL_TREE;
105338fd1498Szrj   switch (node->simdclone->args[i].arg_type)
105438fd1498Szrj     {
105538fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
105638fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
105738fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
105838fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
105938fd1498Szrj       return build_int_cst (addtype, node->simdclone->args[i].linear_step);
106038fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
106138fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
106238fd1498Szrj       ptype = TREE_TYPE (node->simdclone->args[i].orig_arg);
106338fd1498Szrj       break;
106438fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
106538fd1498Szrj     case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
106638fd1498Szrj       ptype = TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg));
106738fd1498Szrj       break;
106838fd1498Szrj     default:
106938fd1498Szrj       gcc_unreachable ();
107038fd1498Szrj     }
107138fd1498Szrj 
107238fd1498Szrj   unsigned int idx = node->simdclone->args[i].linear_step;
107338fd1498Szrj   tree arg = node->simdclone->args[idx].orig_arg;
107438fd1498Szrj   gcc_assert (is_gimple_reg_type (TREE_TYPE (arg)));
107538fd1498Szrj   gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
107638fd1498Szrj   gimple *g;
107738fd1498Szrj   tree ret;
107838fd1498Szrj   if (is_gimple_reg (arg))
107938fd1498Szrj     ret = get_or_create_ssa_default_def (cfun, arg);
108038fd1498Szrj   else
108138fd1498Szrj     {
108238fd1498Szrj       g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
108338fd1498Szrj       gsi_insert_before (&gsi, g, GSI_SAME_STMT);
108438fd1498Szrj       ret = gimple_assign_lhs (g);
108538fd1498Szrj     }
108638fd1498Szrj   if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
108738fd1498Szrj     {
108838fd1498Szrj       g = gimple_build_assign (make_ssa_name (TREE_TYPE (TREE_TYPE (arg))),
108938fd1498Szrj 			       build_simple_mem_ref (ret));
109038fd1498Szrj       gsi_insert_before (&gsi, g, GSI_SAME_STMT);
109138fd1498Szrj       ret = gimple_assign_lhs (g);
109238fd1498Szrj     }
109338fd1498Szrj   if (!useless_type_conversion_p (addtype, TREE_TYPE (ret)))
109438fd1498Szrj     {
109538fd1498Szrj       g = gimple_build_assign (make_ssa_name (addtype), NOP_EXPR, ret);
109638fd1498Szrj       gsi_insert_before (&gsi, g, GSI_SAME_STMT);
109738fd1498Szrj       ret = gimple_assign_lhs (g);
109838fd1498Szrj     }
109938fd1498Szrj   if (POINTER_TYPE_P (ptype))
110038fd1498Szrj     {
110138fd1498Szrj       tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptype));
110238fd1498Szrj       if (size && TREE_CODE (size) == INTEGER_CST)
110338fd1498Szrj 	{
110438fd1498Szrj 	  g = gimple_build_assign (make_ssa_name (addtype), MULT_EXPR,
110538fd1498Szrj 				   ret, fold_convert (addtype, size));
110638fd1498Szrj 	  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
110738fd1498Szrj 	  ret = gimple_assign_lhs (g);
110838fd1498Szrj 	}
110938fd1498Szrj     }
111038fd1498Szrj   return ret;
111138fd1498Szrj }
111238fd1498Szrj 
111338fd1498Szrj /* Adjust the argument types in NODE to their appropriate vector
111438fd1498Szrj    counterparts.  */
111538fd1498Szrj 
111638fd1498Szrj static void
simd_clone_adjust(struct cgraph_node * node)111738fd1498Szrj simd_clone_adjust (struct cgraph_node *node)
111838fd1498Szrj {
111938fd1498Szrj   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
112038fd1498Szrj 
112138fd1498Szrj   targetm.simd_clone.adjust (node);
112238fd1498Szrj 
112338fd1498Szrj   tree retval = simd_clone_adjust_return_type (node);
112438fd1498Szrj   ipa_parm_adjustment_vec adjustments
112538fd1498Szrj     = simd_clone_adjust_argument_types (node);
112638fd1498Szrj 
112738fd1498Szrj   push_gimplify_context ();
112838fd1498Szrj 
112938fd1498Szrj   gimple_seq seq = simd_clone_init_simd_arrays (node, adjustments);
113038fd1498Szrj 
113138fd1498Szrj   /* Adjust all uses of vector arguments accordingly.  Adjust all
113238fd1498Szrj      return values accordingly.  */
113338fd1498Szrj   tree iter = create_tmp_var (unsigned_type_node, "iter");
113438fd1498Szrj   tree iter1 = make_ssa_name (iter);
113538fd1498Szrj   tree iter2 = NULL_TREE;
113638fd1498Szrj   ipa_simd_modify_function_body (node, adjustments, retval, iter1);
113738fd1498Szrj   adjustments.release ();
113838fd1498Szrj 
113938fd1498Szrj   /* Initialize the iteration variable.  */
114038fd1498Szrj   basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
114138fd1498Szrj   basic_block body_bb = split_block_after_labels (entry_bb)->dest;
114238fd1498Szrj   gimple_stmt_iterator gsi = gsi_after_labels (entry_bb);
114338fd1498Szrj   /* Insert the SIMD array and iv initialization at function
114438fd1498Szrj      entry.  */
114538fd1498Szrj   gsi_insert_seq_before (&gsi, seq, GSI_NEW_STMT);
114638fd1498Szrj 
114738fd1498Szrj   pop_gimplify_context (NULL);
114838fd1498Szrj 
114938fd1498Szrj   gimple *g;
115038fd1498Szrj   basic_block incr_bb = NULL;
115138fd1498Szrj   struct loop *loop = NULL;
115238fd1498Szrj 
115338fd1498Szrj   /* Create a new BB right before the original exit BB, to hold the
115438fd1498Szrj      iteration increment and the condition/branch.  */
115538fd1498Szrj   if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
115638fd1498Szrj     {
115738fd1498Szrj       basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
115838fd1498Szrj       incr_bb = create_empty_bb (orig_exit);
115938fd1498Szrj       incr_bb->count = profile_count::zero ();
116038fd1498Szrj       add_bb_to_loop (incr_bb, body_bb->loop_father);
1161*58e805e6Szrj       while (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
116238fd1498Szrj 	{
1163*58e805e6Szrj 	  edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
116438fd1498Szrj 	  redirect_edge_succ (e, incr_bb);
116538fd1498Szrj 	  incr_bb->count += e->count ();
116638fd1498Szrj 	}
116738fd1498Szrj     }
116838fd1498Szrj   else if (node->simdclone->inbranch)
116938fd1498Szrj     {
117038fd1498Szrj       incr_bb = create_empty_bb (entry_bb);
117138fd1498Szrj       incr_bb->count = profile_count::zero ();
117238fd1498Szrj       add_bb_to_loop (incr_bb, body_bb->loop_father);
117338fd1498Szrj     }
117438fd1498Szrj 
117538fd1498Szrj   if (incr_bb)
117638fd1498Szrj     {
117738fd1498Szrj       make_single_succ_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
117838fd1498Szrj       gsi = gsi_last_bb (incr_bb);
117938fd1498Szrj       iter2 = make_ssa_name (iter);
118038fd1498Szrj       g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
118138fd1498Szrj 			       build_int_cst (unsigned_type_node, 1));
118238fd1498Szrj       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
118338fd1498Szrj 
118438fd1498Szrj       /* Mostly annotate the loop for the vectorizer (the rest is done
118538fd1498Szrj 	 below).  */
118638fd1498Szrj       loop = alloc_loop ();
118738fd1498Szrj       cfun->has_force_vectorize_loops = true;
118838fd1498Szrj       loop->safelen = node->simdclone->simdlen;
118938fd1498Szrj       loop->force_vectorize = true;
119038fd1498Szrj       loop->header = body_bb;
119138fd1498Szrj     }
119238fd1498Szrj 
119338fd1498Szrj   /* Branch around the body if the mask applies.  */
119438fd1498Szrj   if (node->simdclone->inbranch)
119538fd1498Szrj     {
119638fd1498Szrj       gsi = gsi_last_bb (loop->header);
119738fd1498Szrj       tree mask_array
119838fd1498Szrj 	= node->simdclone->args[node->simdclone->nargs - 1].simd_array;
119938fd1498Szrj       tree mask;
120038fd1498Szrj       if (node->simdclone->mask_mode != VOIDmode)
120138fd1498Szrj 	{
120238fd1498Szrj 	  tree shift_cnt;
120338fd1498Szrj 	  if (mask_array == NULL_TREE)
120438fd1498Szrj 	    {
120538fd1498Szrj 	      tree arg = node->simdclone->args[node->simdclone->nargs
120638fd1498Szrj 					       - 1].vector_arg;
120738fd1498Szrj 	      mask = get_or_create_ssa_default_def (cfun, arg);
120838fd1498Szrj 	      shift_cnt = iter1;
120938fd1498Szrj 	    }
121038fd1498Szrj 	  else
121138fd1498Szrj 	    {
121238fd1498Szrj 	      tree maskt = TREE_TYPE (mask_array);
121338fd1498Szrj 	      int c = tree_to_uhwi (TYPE_MAX_VALUE (TYPE_DOMAIN (maskt)));
121438fd1498Szrj 	      c = node->simdclone->simdlen / (c + 1);
121538fd1498Szrj 	      int s = exact_log2 (c);
121638fd1498Szrj 	      gcc_assert (s > 0);
121738fd1498Szrj 	      c--;
121838fd1498Szrj 	      tree idx = make_ssa_name (TREE_TYPE (iter1));
121938fd1498Szrj 	      g = gimple_build_assign (idx, RSHIFT_EXPR, iter1,
122038fd1498Szrj 				       build_int_cst (NULL_TREE, s));
122138fd1498Szrj 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
122238fd1498Szrj 	      mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
122338fd1498Szrj 	      tree aref = build4 (ARRAY_REF,
122438fd1498Szrj 				  TREE_TYPE (TREE_TYPE (mask_array)),
122538fd1498Szrj 				  mask_array, idx, NULL, NULL);
122638fd1498Szrj 	      g = gimple_build_assign (mask, aref);
122738fd1498Szrj 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
122838fd1498Szrj 	      shift_cnt = make_ssa_name (TREE_TYPE (iter1));
122938fd1498Szrj 	      g = gimple_build_assign (shift_cnt, BIT_AND_EXPR, iter1,
123038fd1498Szrj 				       build_int_cst (TREE_TYPE (iter1), c));
123138fd1498Szrj 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
123238fd1498Szrj 	    }
123338fd1498Szrj 	  g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
123438fd1498Szrj 				   RSHIFT_EXPR, mask, shift_cnt);
123538fd1498Szrj 	  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
123638fd1498Szrj 	  mask = gimple_assign_lhs (g);
123738fd1498Szrj 	  g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)),
123838fd1498Szrj 				   BIT_AND_EXPR, mask,
123938fd1498Szrj 				   build_int_cst (TREE_TYPE (mask), 1));
124038fd1498Szrj 	  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
124138fd1498Szrj 	  mask = gimple_assign_lhs (g);
124238fd1498Szrj 	}
124338fd1498Szrj       else
124438fd1498Szrj 	{
124538fd1498Szrj 	  mask = make_ssa_name (TREE_TYPE (TREE_TYPE (mask_array)));
124638fd1498Szrj 	  tree aref = build4 (ARRAY_REF,
124738fd1498Szrj 			      TREE_TYPE (TREE_TYPE (mask_array)),
124838fd1498Szrj 			      mask_array, iter1, NULL, NULL);
124938fd1498Szrj 	  g = gimple_build_assign (mask, aref);
125038fd1498Szrj 	  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
125138fd1498Szrj 	  int bitsize = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (aref)));
125238fd1498Szrj 	  if (!INTEGRAL_TYPE_P (TREE_TYPE (aref)))
125338fd1498Szrj 	    {
125438fd1498Szrj 	      aref = build1 (VIEW_CONVERT_EXPR,
125538fd1498Szrj 			     build_nonstandard_integer_type (bitsize, 0),
125638fd1498Szrj 							     mask);
125738fd1498Szrj 	      mask = make_ssa_name (TREE_TYPE (aref));
125838fd1498Szrj 	      g = gimple_build_assign (mask, aref);
125938fd1498Szrj 	      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
126038fd1498Szrj 	    }
126138fd1498Szrj 	}
126238fd1498Szrj 
126338fd1498Szrj       g = gimple_build_cond (EQ_EXPR, mask, build_zero_cst (TREE_TYPE (mask)),
126438fd1498Szrj 			     NULL, NULL);
126538fd1498Szrj       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
126638fd1498Szrj       edge e = make_edge (loop->header, incr_bb, EDGE_TRUE_VALUE);
126738fd1498Szrj       e->probability = profile_probability::unlikely ().guessed ();
126838fd1498Szrj       incr_bb->count += e->count ();
126938fd1498Szrj       edge fallthru = FALLTHRU_EDGE (loop->header);
127038fd1498Szrj       fallthru->flags = EDGE_FALSE_VALUE;
127138fd1498Szrj       fallthru->probability = profile_probability::likely ().guessed ();
127238fd1498Szrj     }
127338fd1498Szrj 
127438fd1498Szrj   basic_block latch_bb = NULL;
127538fd1498Szrj   basic_block new_exit_bb = NULL;
127638fd1498Szrj 
127738fd1498Szrj   /* Generate the condition.  */
127838fd1498Szrj   if (incr_bb)
127938fd1498Szrj     {
128038fd1498Szrj       gsi = gsi_last_bb (incr_bb);
128138fd1498Szrj       g = gimple_build_cond (LT_EXPR, iter2,
128238fd1498Szrj 			     build_int_cst (unsigned_type_node,
128338fd1498Szrj 					    node->simdclone->simdlen),
128438fd1498Szrj 			     NULL, NULL);
128538fd1498Szrj       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
128638fd1498Szrj       edge e = split_block (incr_bb, gsi_stmt (gsi));
128738fd1498Szrj       latch_bb = e->dest;
128838fd1498Szrj       new_exit_bb = split_block_after_labels (latch_bb)->dest;
128938fd1498Szrj       loop->latch = latch_bb;
129038fd1498Szrj 
129138fd1498Szrj       redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
129238fd1498Szrj 
129338fd1498Szrj       edge new_e = make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
129438fd1498Szrj 
129538fd1498Szrj       /* FIXME: Do we need to distribute probabilities for the conditional? */
129638fd1498Szrj       new_e->probability = profile_probability::guessed_never ();
129738fd1498Szrj       /* The successor of incr_bb is already pointing to latch_bb; just
129838fd1498Szrj 	 change the flags.
129938fd1498Szrj 	 make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE);  */
130038fd1498Szrj       FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
130138fd1498Szrj     }
130238fd1498Szrj 
130338fd1498Szrj   gphi *phi = create_phi_node (iter1, body_bb);
130438fd1498Szrj   edge preheader_edge = find_edge (entry_bb, body_bb);
130538fd1498Szrj   edge latch_edge = NULL;
130638fd1498Szrj   add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
130738fd1498Szrj 	       UNKNOWN_LOCATION);
130838fd1498Szrj   if (incr_bb)
130938fd1498Szrj     {
131038fd1498Szrj       latch_edge = single_succ_edge (latch_bb);
131138fd1498Szrj       add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
131238fd1498Szrj 
131338fd1498Szrj       /* Generate the new return.  */
131438fd1498Szrj       gsi = gsi_last_bb (new_exit_bb);
131538fd1498Szrj       if (retval
131638fd1498Szrj 	  && TREE_CODE (retval) == VIEW_CONVERT_EXPR
131738fd1498Szrj 	  && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
131838fd1498Szrj 	retval = TREE_OPERAND (retval, 0);
131938fd1498Szrj       else if (retval)
132038fd1498Szrj 	{
132138fd1498Szrj 	  retval = build1 (VIEW_CONVERT_EXPR,
132238fd1498Szrj 			   TREE_TYPE (TREE_TYPE (node->decl)),
132338fd1498Szrj 			   retval);
132438fd1498Szrj 	  retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
132538fd1498Szrj 					     false, GSI_CONTINUE_LINKING);
132638fd1498Szrj 	}
132738fd1498Szrj       g = gimple_build_return (retval);
132838fd1498Szrj       gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
132938fd1498Szrj     }
133038fd1498Szrj 
133138fd1498Szrj   /* Handle aligned clauses by replacing default defs of the aligned
133238fd1498Szrj      uniform args with __builtin_assume_aligned (arg_N(D), alignment)
133338fd1498Szrj      lhs.  Handle linear by adding PHIs.  */
133438fd1498Szrj   for (unsigned i = 0; i < node->simdclone->nargs; i++)
133538fd1498Szrj     if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
133638fd1498Szrj 	&& (TREE_ADDRESSABLE (node->simdclone->args[i].orig_arg)
133738fd1498Szrj 	    || !is_gimple_reg_type
133838fd1498Szrj 			(TREE_TYPE (node->simdclone->args[i].orig_arg))))
133938fd1498Szrj       {
134038fd1498Szrj 	tree orig_arg = node->simdclone->args[i].orig_arg;
134138fd1498Szrj 	if (is_gimple_reg_type (TREE_TYPE (orig_arg)))
134238fd1498Szrj 	  iter1 = make_ssa_name (TREE_TYPE (orig_arg));
134338fd1498Szrj 	else
134438fd1498Szrj 	  {
134538fd1498Szrj 	    iter1 = create_tmp_var_raw (TREE_TYPE (orig_arg));
134638fd1498Szrj 	    gimple_add_tmp_var (iter1);
134738fd1498Szrj 	  }
134838fd1498Szrj 	gsi = gsi_after_labels (entry_bb);
134938fd1498Szrj 	g = gimple_build_assign (iter1, orig_arg);
135038fd1498Szrj 	gsi_insert_before (&gsi, g, GSI_NEW_STMT);
135138fd1498Szrj 	gsi = gsi_after_labels (body_bb);
135238fd1498Szrj 	g = gimple_build_assign (orig_arg, iter1);
135338fd1498Szrj 	gsi_insert_before (&gsi, g, GSI_NEW_STMT);
135438fd1498Szrj       }
135538fd1498Szrj     else if (node->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_UNIFORM
135638fd1498Szrj 	     && DECL_BY_REFERENCE (node->simdclone->args[i].orig_arg)
135738fd1498Szrj 	     && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
135838fd1498Szrj 		== REFERENCE_TYPE
135938fd1498Szrj 	     && TREE_ADDRESSABLE
136038fd1498Szrj 		  (TREE_TYPE (TREE_TYPE (node->simdclone->args[i].orig_arg))))
136138fd1498Szrj       {
136238fd1498Szrj 	tree orig_arg = node->simdclone->args[i].orig_arg;
136338fd1498Szrj 	tree def = ssa_default_def (cfun, orig_arg);
136438fd1498Szrj 	if (def && !has_zero_uses (def))
136538fd1498Szrj 	  {
136638fd1498Szrj 	    iter1 = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (orig_arg)));
136738fd1498Szrj 	    gimple_add_tmp_var (iter1);
136838fd1498Szrj 	    gsi = gsi_after_labels (entry_bb);
136938fd1498Szrj 	    g = gimple_build_assign (iter1, build_simple_mem_ref (def));
137038fd1498Szrj 	    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
137138fd1498Szrj 	    gsi = gsi_after_labels (body_bb);
137238fd1498Szrj 	    g = gimple_build_assign (build_simple_mem_ref (def), iter1);
137338fd1498Szrj 	    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
137438fd1498Szrj 	  }
137538fd1498Szrj       }
137638fd1498Szrj     else if (node->simdclone->args[i].alignment
137738fd1498Szrj 	     && node->simdclone->args[i].arg_type
137838fd1498Szrj 		== SIMD_CLONE_ARG_TYPE_UNIFORM
137938fd1498Szrj 	     && (node->simdclone->args[i].alignment
138038fd1498Szrj 		 & (node->simdclone->args[i].alignment - 1)) == 0
138138fd1498Szrj 	     && TREE_CODE (TREE_TYPE (node->simdclone->args[i].orig_arg))
138238fd1498Szrj 		== POINTER_TYPE)
138338fd1498Szrj       {
138438fd1498Szrj 	unsigned int alignment = node->simdclone->args[i].alignment;
138538fd1498Szrj 	tree orig_arg = node->simdclone->args[i].orig_arg;
138638fd1498Szrj 	tree def = ssa_default_def (cfun, orig_arg);
138738fd1498Szrj 	if (def && !has_zero_uses (def))
138838fd1498Szrj 	  {
138938fd1498Szrj 	    tree fn = builtin_decl_explicit (BUILT_IN_ASSUME_ALIGNED);
139038fd1498Szrj 	    gimple_seq seq = NULL;
139138fd1498Szrj 	    bool need_cvt = false;
139238fd1498Szrj 	    gcall *call
139338fd1498Szrj 	      = gimple_build_call (fn, 2, def, size_int (alignment));
139438fd1498Szrj 	    g = call;
139538fd1498Szrj 	    if (!useless_type_conversion_p (TREE_TYPE (orig_arg),
139638fd1498Szrj 					    ptr_type_node))
139738fd1498Szrj 	      need_cvt = true;
139838fd1498Szrj 	    tree t = make_ssa_name (need_cvt ? ptr_type_node : orig_arg);
139938fd1498Szrj 	    gimple_call_set_lhs (g, t);
140038fd1498Szrj 	    gimple_seq_add_stmt_without_update (&seq, g);
140138fd1498Szrj 	    if (need_cvt)
140238fd1498Szrj 	      {
140338fd1498Szrj 		t = make_ssa_name (orig_arg);
140438fd1498Szrj 		g = gimple_build_assign (t, NOP_EXPR, gimple_call_lhs (g));
140538fd1498Szrj 		gimple_seq_add_stmt_without_update (&seq, g);
140638fd1498Szrj 	      }
140738fd1498Szrj 	    gsi_insert_seq_on_edge_immediate
140838fd1498Szrj 	      (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
140938fd1498Szrj 
141038fd1498Szrj 	    entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
141138fd1498Szrj 	    node->create_edge (cgraph_node::get_create (fn),
141238fd1498Szrj 			       call, entry_bb->count);
141338fd1498Szrj 
141438fd1498Szrj 	    imm_use_iterator iter;
141538fd1498Szrj 	    use_operand_p use_p;
141638fd1498Szrj 	    gimple *use_stmt;
141738fd1498Szrj 	    tree repl = gimple_get_lhs (g);
141838fd1498Szrj 	    FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
141938fd1498Szrj 	      if (is_gimple_debug (use_stmt) || use_stmt == call)
142038fd1498Szrj 		continue;
142138fd1498Szrj 	      else
142238fd1498Szrj 		FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
142338fd1498Szrj 		  SET_USE (use_p, repl);
142438fd1498Szrj 	  }
142538fd1498Szrj       }
142638fd1498Szrj     else if ((node->simdclone->args[i].arg_type
142738fd1498Szrj 	      == SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP)
142838fd1498Szrj 	     || (node->simdclone->args[i].arg_type
142938fd1498Szrj 		 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP)
143038fd1498Szrj 	     || (node->simdclone->args[i].arg_type
143138fd1498Szrj 		 == SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP)
143238fd1498Szrj 	     || (node->simdclone->args[i].arg_type
143338fd1498Szrj 		 == SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP))
143438fd1498Szrj       {
143538fd1498Szrj 	tree orig_arg = node->simdclone->args[i].orig_arg;
143638fd1498Szrj 	gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
143738fd1498Szrj 		    || POINTER_TYPE_P (TREE_TYPE (orig_arg)));
143838fd1498Szrj 	tree def = NULL_TREE;
143938fd1498Szrj 	if (TREE_ADDRESSABLE (orig_arg))
144038fd1498Szrj 	  {
144138fd1498Szrj 	    def = make_ssa_name (TREE_TYPE (orig_arg));
144238fd1498Szrj 	    iter1 = make_ssa_name (TREE_TYPE (orig_arg));
144338fd1498Szrj 	    if (incr_bb)
144438fd1498Szrj 	      iter2 = make_ssa_name (TREE_TYPE (orig_arg));
144538fd1498Szrj 	    gsi = gsi_after_labels (entry_bb);
144638fd1498Szrj 	    g = gimple_build_assign (def, orig_arg);
144738fd1498Szrj 	    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
144838fd1498Szrj 	  }
144938fd1498Szrj 	else
145038fd1498Szrj 	  {
145138fd1498Szrj 	    def = ssa_default_def (cfun, orig_arg);
145238fd1498Szrj 	    if (!def || has_zero_uses (def))
145338fd1498Szrj 	      def = NULL_TREE;
145438fd1498Szrj 	    else
145538fd1498Szrj 	      {
145638fd1498Szrj 		iter1 = make_ssa_name (orig_arg);
145738fd1498Szrj 		if (incr_bb)
145838fd1498Szrj 		  iter2 = make_ssa_name (orig_arg);
145938fd1498Szrj 	      }
146038fd1498Szrj 	  }
146138fd1498Szrj 	if (def)
146238fd1498Szrj 	  {
146338fd1498Szrj 	    phi = create_phi_node (iter1, body_bb);
146438fd1498Szrj 	    add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
146538fd1498Szrj 	    if (incr_bb)
146638fd1498Szrj 	      {
146738fd1498Szrj 		add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
146838fd1498Szrj 		enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
146938fd1498Szrj 				      ? PLUS_EXPR : POINTER_PLUS_EXPR;
147038fd1498Szrj 		tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
147138fd1498Szrj 			       ? TREE_TYPE (orig_arg) : sizetype;
147238fd1498Szrj 		tree addcst = simd_clone_linear_addend (node, i, addtype,
147338fd1498Szrj 							entry_bb);
147438fd1498Szrj 		gsi = gsi_last_bb (incr_bb);
147538fd1498Szrj 		g = gimple_build_assign (iter2, code, iter1, addcst);
147638fd1498Szrj 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
147738fd1498Szrj 	      }
147838fd1498Szrj 
147938fd1498Szrj 	    imm_use_iterator iter;
148038fd1498Szrj 	    use_operand_p use_p;
148138fd1498Szrj 	    gimple *use_stmt;
148238fd1498Szrj 	    if (TREE_ADDRESSABLE (orig_arg))
148338fd1498Szrj 	      {
148438fd1498Szrj 		gsi = gsi_after_labels (body_bb);
148538fd1498Szrj 		g = gimple_build_assign (orig_arg, iter1);
148638fd1498Szrj 		gsi_insert_before (&gsi, g, GSI_NEW_STMT);
148738fd1498Szrj 	      }
148838fd1498Szrj 	    else
148938fd1498Szrj 	      FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
149038fd1498Szrj 		if (use_stmt == phi)
149138fd1498Szrj 		  continue;
149238fd1498Szrj 		else
149338fd1498Szrj 		  FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
149438fd1498Szrj 		    SET_USE (use_p, iter1);
149538fd1498Szrj 	  }
149638fd1498Szrj       }
149738fd1498Szrj     else if (node->simdclone->args[i].arg_type
149838fd1498Szrj 	     == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP
149938fd1498Szrj 	     || (node->simdclone->args[i].arg_type
150038fd1498Szrj 		 == SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP))
150138fd1498Szrj       {
150238fd1498Szrj 	tree orig_arg = node->simdclone->args[i].orig_arg;
150338fd1498Szrj 	tree def = ssa_default_def (cfun, orig_arg);
150438fd1498Szrj 	gcc_assert (!TREE_ADDRESSABLE (orig_arg)
150538fd1498Szrj 		    && TREE_CODE (TREE_TYPE (orig_arg)) == REFERENCE_TYPE);
150638fd1498Szrj 	if (def && !has_zero_uses (def))
150738fd1498Szrj 	  {
150838fd1498Szrj 	    tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
150938fd1498Szrj 	    iter1 = make_ssa_name (orig_arg);
151038fd1498Szrj 	    if (incr_bb)
151138fd1498Szrj 	      iter2 = make_ssa_name (orig_arg);
151238fd1498Szrj 	    tree iter3 = make_ssa_name (rtype);
151338fd1498Szrj 	    tree iter4 = make_ssa_name (rtype);
151438fd1498Szrj 	    tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
151538fd1498Szrj 	    gsi = gsi_after_labels (entry_bb);
151638fd1498Szrj 	    gimple *load
151738fd1498Szrj 	      = gimple_build_assign (iter3, build_simple_mem_ref (def));
151838fd1498Szrj 	    gsi_insert_before (&gsi, load, GSI_NEW_STMT);
151938fd1498Szrj 
152038fd1498Szrj 	    tree array = node->simdclone->args[i].simd_array;
152138fd1498Szrj 	    TREE_ADDRESSABLE (array) = 1;
152238fd1498Szrj 	    tree ptr = build_fold_addr_expr (array);
152338fd1498Szrj 	    phi = create_phi_node (iter1, body_bb);
152438fd1498Szrj 	    add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
152538fd1498Szrj 	    if (incr_bb)
152638fd1498Szrj 	      {
152738fd1498Szrj 		add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
152838fd1498Szrj 		g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
152938fd1498Szrj 					 TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
153038fd1498Szrj 		gsi = gsi_last_bb (incr_bb);
153138fd1498Szrj 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
153238fd1498Szrj 	      }
153338fd1498Szrj 
153438fd1498Szrj 	    phi = create_phi_node (iter4, body_bb);
153538fd1498Szrj 	    add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
153638fd1498Szrj 	    if (incr_bb)
153738fd1498Szrj 	      {
153838fd1498Szrj 		add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
153938fd1498Szrj 		enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
154038fd1498Szrj 				      ? PLUS_EXPR : POINTER_PLUS_EXPR;
154138fd1498Szrj 		tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
154238fd1498Szrj 			       ? TREE_TYPE (iter3) : sizetype;
154338fd1498Szrj 		tree addcst = simd_clone_linear_addend (node, i, addtype,
154438fd1498Szrj 							entry_bb);
154538fd1498Szrj 		g = gimple_build_assign (iter5, code, iter4, addcst);
154638fd1498Szrj 		gsi = gsi_last_bb (incr_bb);
154738fd1498Szrj 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
154838fd1498Szrj 	      }
154938fd1498Szrj 
155038fd1498Szrj 	    g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
155138fd1498Szrj 	    gsi = gsi_after_labels (body_bb);
155238fd1498Szrj 	    gsi_insert_before (&gsi, g, GSI_SAME_STMT);
155338fd1498Szrj 
155438fd1498Szrj 	    imm_use_iterator iter;
155538fd1498Szrj 	    use_operand_p use_p;
155638fd1498Szrj 	    gimple *use_stmt;
155738fd1498Szrj 	    FOR_EACH_IMM_USE_STMT (use_stmt, iter, def)
155838fd1498Szrj 	      if (use_stmt == load)
155938fd1498Szrj 		continue;
156038fd1498Szrj 	      else
156138fd1498Szrj 		FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
156238fd1498Szrj 		  SET_USE (use_p, iter1);
156338fd1498Szrj 
156438fd1498Szrj 	    if (!TYPE_READONLY (rtype) && incr_bb)
156538fd1498Szrj 	      {
156638fd1498Szrj 		tree v = make_ssa_name (rtype);
156738fd1498Szrj 		tree aref = build4 (ARRAY_REF, rtype, array,
156838fd1498Szrj 				    size_zero_node, NULL_TREE,
156938fd1498Szrj 				    NULL_TREE);
157038fd1498Szrj 		gsi = gsi_after_labels (new_exit_bb);
157138fd1498Szrj 		g = gimple_build_assign (v, aref);
157238fd1498Szrj 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
157338fd1498Szrj 		g = gimple_build_assign (build_simple_mem_ref (def), v);
157438fd1498Szrj 		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
157538fd1498Szrj 	      }
157638fd1498Szrj 	  }
157738fd1498Szrj       }
157838fd1498Szrj 
157938fd1498Szrj   calculate_dominance_info (CDI_DOMINATORS);
158038fd1498Szrj   if (loop)
158138fd1498Szrj     add_loop (loop, loop->header->loop_father);
158238fd1498Szrj   update_ssa (TODO_update_ssa);
158338fd1498Szrj 
158438fd1498Szrj   pop_cfun ();
158538fd1498Szrj }
158638fd1498Szrj 
158738fd1498Szrj /* If the function in NODE is tagged as an elemental SIMD function,
158838fd1498Szrj    create the appropriate SIMD clones.  */
158938fd1498Szrj 
159038fd1498Szrj void
expand_simd_clones(struct cgraph_node * node)159138fd1498Szrj expand_simd_clones (struct cgraph_node *node)
159238fd1498Szrj {
159338fd1498Szrj   tree attr = lookup_attribute ("omp declare simd",
159438fd1498Szrj 				DECL_ATTRIBUTES (node->decl));
159538fd1498Szrj   if (attr == NULL_TREE
159638fd1498Szrj       || node->global.inlined_to
159738fd1498Szrj       || lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
159838fd1498Szrj     return;
159938fd1498Szrj 
160038fd1498Szrj   /* Ignore
160138fd1498Szrj      #pragma omp declare simd
160238fd1498Szrj      extern int foo ();
160338fd1498Szrj      in C, there we don't know the argument types at all.  */
160438fd1498Szrj   if (!node->definition
160538fd1498Szrj       && TYPE_ARG_TYPES (TREE_TYPE (node->decl)) == NULL_TREE)
160638fd1498Szrj     return;
160738fd1498Szrj 
160838fd1498Szrj   /* Call this before creating clone_info, as it might ggc_collect.  */
160938fd1498Szrj   if (node->definition && node->has_gimple_body_p ())
161038fd1498Szrj     node->get_body ();
161138fd1498Szrj 
161238fd1498Szrj   do
161338fd1498Szrj     {
161438fd1498Szrj       /* Start with parsing the "omp declare simd" attribute(s).  */
161538fd1498Szrj       bool inbranch_clause_specified;
161638fd1498Szrj       struct cgraph_simd_clone *clone_info
161738fd1498Szrj 	= simd_clone_clauses_extract (node, TREE_VALUE (attr),
161838fd1498Szrj 				      &inbranch_clause_specified);
161938fd1498Szrj       if (clone_info == NULL)
162038fd1498Szrj 	continue;
162138fd1498Szrj 
162238fd1498Szrj       int orig_simdlen = clone_info->simdlen;
162338fd1498Szrj       tree base_type = simd_clone_compute_base_data_type (node, clone_info);
162438fd1498Szrj       /* The target can return 0 (no simd clones should be created),
162538fd1498Szrj 	 1 (just one ISA of simd clones should be created) or higher
162638fd1498Szrj 	 count of ISA variants.  In that case, clone_info is initialized
162738fd1498Szrj 	 for the first ISA variant.  */
162838fd1498Szrj       int count
162938fd1498Szrj 	= targetm.simd_clone.compute_vecsize_and_simdlen (node, clone_info,
163038fd1498Szrj 							  base_type, 0);
163138fd1498Szrj       if (count == 0)
163238fd1498Szrj 	continue;
163338fd1498Szrj 
163438fd1498Szrj       /* Loop over all COUNT ISA variants, and if !INBRANCH_CLAUSE_SPECIFIED,
163538fd1498Szrj 	 also create one inbranch and one !inbranch clone of it.  */
163638fd1498Szrj       for (int i = 0; i < count * 2; i++)
163738fd1498Szrj 	{
163838fd1498Szrj 	  struct cgraph_simd_clone *clone = clone_info;
163938fd1498Szrj 	  if (inbranch_clause_specified && (i & 1) != 0)
164038fd1498Szrj 	    continue;
164138fd1498Szrj 
164238fd1498Szrj 	  if (i != 0)
164338fd1498Szrj 	    {
164438fd1498Szrj 	      clone = simd_clone_struct_alloc (clone_info->nargs
164538fd1498Szrj 					       + ((i & 1) != 0));
164638fd1498Szrj 	      simd_clone_struct_copy (clone, clone_info);
164738fd1498Szrj 	      /* Undo changes targetm.simd_clone.compute_vecsize_and_simdlen
164838fd1498Szrj 		 and simd_clone_adjust_argument_types did to the first
164938fd1498Szrj 		 clone's info.  */
165038fd1498Szrj 	      clone->nargs -= clone_info->inbranch;
165138fd1498Szrj 	      clone->simdlen = orig_simdlen;
165238fd1498Szrj 	      /* And call the target hook again to get the right ISA.  */
165338fd1498Szrj 	      targetm.simd_clone.compute_vecsize_and_simdlen (node, clone,
165438fd1498Szrj 							      base_type,
165538fd1498Szrj 							      i / 2);
165638fd1498Szrj 	      if ((i & 1) != 0)
165738fd1498Szrj 		clone->inbranch = 1;
165838fd1498Szrj 	    }
165938fd1498Szrj 
166038fd1498Szrj 	  /* simd_clone_mangle might fail if such a clone has been created
166138fd1498Szrj 	     already.  */
166238fd1498Szrj 	  tree id = simd_clone_mangle (node, clone);
166338fd1498Szrj 	  if (id == NULL_TREE)
166438fd1498Szrj 	    continue;
166538fd1498Szrj 
166638fd1498Szrj 	  /* Only when we are sure we want to create the clone actually
166738fd1498Szrj 	     clone the function (or definitions) or create another
166838fd1498Szrj 	     extern FUNCTION_DECL (for prototypes without definitions).  */
166938fd1498Szrj 	  struct cgraph_node *n = simd_clone_create (node);
167038fd1498Szrj 	  if (n == NULL)
167138fd1498Szrj 	    continue;
167238fd1498Szrj 
167338fd1498Szrj 	  n->simdclone = clone;
167438fd1498Szrj 	  clone->origin = node;
167538fd1498Szrj 	  clone->next_clone = NULL;
167638fd1498Szrj 	  if (node->simd_clones == NULL)
167738fd1498Szrj 	    {
167838fd1498Szrj 	      clone->prev_clone = n;
167938fd1498Szrj 	      node->simd_clones = n;
168038fd1498Szrj 	    }
168138fd1498Szrj 	  else
168238fd1498Szrj 	    {
168338fd1498Szrj 	      clone->prev_clone = node->simd_clones->simdclone->prev_clone;
168438fd1498Szrj 	      clone->prev_clone->simdclone->next_clone = n;
168538fd1498Szrj 	      node->simd_clones->simdclone->prev_clone = n;
168638fd1498Szrj 	    }
168738fd1498Szrj 	  symtab->change_decl_assembler_name (n->decl, id);
168838fd1498Szrj 	  /* And finally adjust the return type, parameters and for
168938fd1498Szrj 	     definitions also function body.  */
169038fd1498Szrj 	  if (node->definition)
169138fd1498Szrj 	    simd_clone_adjust (n);
169238fd1498Szrj 	  else
169338fd1498Szrj 	    {
169438fd1498Szrj 	      simd_clone_adjust_return_type (n);
169538fd1498Szrj 	      simd_clone_adjust_argument_types (n);
169638fd1498Szrj 	    }
169738fd1498Szrj 	}
169838fd1498Szrj     }
169938fd1498Szrj   while ((attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))));
170038fd1498Szrj }
170138fd1498Szrj 
170238fd1498Szrj /* Entry point for IPA simd clone creation pass.  */
170338fd1498Szrj 
170438fd1498Szrj static unsigned int
ipa_omp_simd_clone(void)170538fd1498Szrj ipa_omp_simd_clone (void)
170638fd1498Szrj {
170738fd1498Szrj   struct cgraph_node *node;
170838fd1498Szrj   FOR_EACH_FUNCTION (node)
170938fd1498Szrj     expand_simd_clones (node);
171038fd1498Szrj   return 0;
171138fd1498Szrj }
171238fd1498Szrj 
171338fd1498Szrj namespace {
171438fd1498Szrj 
171538fd1498Szrj const pass_data pass_data_omp_simd_clone =
171638fd1498Szrj {
171738fd1498Szrj   SIMPLE_IPA_PASS,		/* type */
171838fd1498Szrj   "simdclone",			/* name */
171938fd1498Szrj   OPTGROUP_OMP,			/* optinfo_flags */
172038fd1498Szrj   TV_NONE,			/* tv_id */
172138fd1498Szrj   ( PROP_ssa | PROP_cfg ),	/* properties_required */
172238fd1498Szrj   0,				/* properties_provided */
172338fd1498Szrj   0,				/* properties_destroyed */
172438fd1498Szrj   0,				/* todo_flags_start */
172538fd1498Szrj   0,				/* todo_flags_finish */
172638fd1498Szrj };
172738fd1498Szrj 
172838fd1498Szrj class pass_omp_simd_clone : public simple_ipa_opt_pass
172938fd1498Szrj {
173038fd1498Szrj public:
pass_omp_simd_clone(gcc::context * ctxt)173138fd1498Szrj   pass_omp_simd_clone(gcc::context *ctxt)
173238fd1498Szrj     : simple_ipa_opt_pass(pass_data_omp_simd_clone, ctxt)
173338fd1498Szrj   {}
173438fd1498Szrj 
173538fd1498Szrj   /* opt_pass methods: */
173638fd1498Szrj   virtual bool gate (function *);
execute(function *)173738fd1498Szrj   virtual unsigned int execute (function *) { return ipa_omp_simd_clone (); }
173838fd1498Szrj };
173938fd1498Szrj 
174038fd1498Szrj bool
gate(function *)174138fd1498Szrj pass_omp_simd_clone::gate (function *)
174238fd1498Szrj {
174338fd1498Szrj   return targetm.simd_clone.compute_vecsize_and_simdlen != NULL;
174438fd1498Szrj }
174538fd1498Szrj 
174638fd1498Szrj } // anon namespace
174738fd1498Szrj 
174838fd1498Szrj simple_ipa_opt_pass *
make_pass_omp_simd_clone(gcc::context * ctxt)174938fd1498Szrj make_pass_omp_simd_clone (gcc::context *ctxt)
175038fd1498Szrj {
175138fd1498Szrj   return new pass_omp_simd_clone (ctxt);
175238fd1498Szrj }
1753