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