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