From: rsandifo Date: Wed, 4 Dec 2013 12:54:49 +0000 (+0000) Subject: Merge with trunk. X-Git-Tag: upstream/5.3.0~8646^2~69 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bdff91a14bf8e5d18b1eb47bb529894482065762;p=platform%2Fupstream%2Flinaro-gcc.git Merge with trunk. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/wide-int@205668 138bc75d-0d04-0410-961f-82ee72b054a4 --- bdff91a14bf8e5d18b1eb47bb529894482065762 diff --cc gcc/builtins.c index ddca547,4f1c818..91a6bea --- a/gcc/builtins.c +++ b/gcc/builtins.c @@@ -3149,11 -3146,11 +3153,11 @@@ determine_block_size (tree len, rtx len } else if (range_type == VR_ANTI_RANGE) { - /* Anti range 0...N lets us to determine minmal size to N+1. */ + /* Anti range 0...N lets us to determine minimal size to N+1. */ - if (min.is_zero ()) + if (min == 0) { - if ((max + double_int_one).fits_uhwi ()) - *min_size = (max + double_int_one).to_uhwi (); + if (wi::fits_uhwi_p (max) && max.to_uhwi () + 1 != 0) + *min_size = max.to_uhwi () + 1; } /* Code like diff --cc gcc/c-family/c-common.c index e5e9389,e652802..c0fc8be --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@@ -49,9 -48,7 +48,8 @@@ along with GCC; see the file COPYING3 #include "opts.h" #include "cgraph.h" #include "target-def.h" - #include "gimple.h" #include "gimplify.h" +#include "wide-int-print.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ diff --cc gcc/cp/class.c index 027d235,842b11c..6b2efbf --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@@ -38,11 -39,7 +39,8 @@@ along with GCC; see the file COPYING3 #include "cgraph.h" #include "dumpfile.h" #include "splay-tree.h" - #include "pointer-set.h" - #include "hash-table.h" - #include "gimple.h" #include "gimplify.h" +#include "wide-int.h" /* The number of nested classes being processed. If we are not in the scope of any class, this is zero. */ diff --cc gcc/cp/init.c index 7b6f4e2,1e6e691..86b6903 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@@ -30,9 -30,7 +30,8 @@@ along with GCC; see the file COPYING3 #include "cp-tree.h" #include "flags.h" #include "target.h" - #include "gimple.h" #include "gimplify.h" +#include "wide-int.h" static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); diff --cc gcc/cp/tree.c index 2e3b586,cb05633..c3f57d1 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@@ -33,10 -33,9 +33,10 @@@ along with GCC; see the file COPYING3 #include "convert.h" #include "cgraph.h" #include "splay-tree.h" - #include "gimple.h" - #include "gimplify.h" #include "hash-table.h" + #include "gimple-expr.h" + #include "gimplify.h" +#include "wide-int.h" static tree bot_manip (tree *, int *, void *); static tree bot_replace (tree *, int *, void *); diff --cc gcc/doc/tm.texi.in index 55e96bb,7e459eb..3d6a9d0 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@@ -8395,50 -8411,6 +8399,52 @@@ and the associated definitions of thos @hook TARGET_HAS_IFUNC_P + @hook TARGET_ATOMIC_ALIGN_FOR_MODE + @hook TARGET_ATOMIC_ASSIGN_EXPAND_FENV + +@defmac TARGET_SUPPORTS_WIDE_INT + +On older ports, large integers are stored in @code{CONST_DOUBLE} rtl +objects. Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be nonzero +to indicate that large integers are stored in +@code{CONST_WIDE_INT} rtl objects. The @code{CONST_WIDE_INT} allows +very large integer constants to be represented. @code{CONST_DOUBLE} +is limited to twice the size of the host's @code{HOST_WIDE_INT} +representation. + +Converting a port mostly requires looking for the places where +@code{CONST_DOUBLE}s are used with @code{VOIDmode} and replacing that +code with code that accesses @code{CONST_WIDE_INT}s. @samp{"grep -i +const_double"} at the port level gets you to 95% of the changes that +need to be made. There are a few places that require a deeper look. + +@itemize @bullet +@item +There is no equivalent to @code{hval} and @code{lval} for +@code{CONST_WIDE_INT}s. This would be difficult to express in the md +language since there are a variable number of elements. + +Most ports only check that @code{hval} is either 0 or -1 to see if the +value is small. As mentioned above, this will no longer be necessary +since small constants are always @code{CONST_INT}. Of course there +are still a few exceptions, the alpha's constraint used by the zap +instruction certainly requires careful examination by C code. +However, all the current code does is pass the hval and lval to C +code, so evolving the c code to look at the @code{CONST_WIDE_INT} is +not really a large change. + +@item +Because there is no standard template that ports use to materialize +constants, there is likely to be some futzing that is unique to each +port in this code. + +@item +The rtx costs may have to be adjusted to properly account for larger +constants that are represented as @code{CONST_WIDE_INT}. +@end itemize + +All and all it does not take long to convert ports that the +maintainer is familiar with. + +@end defmac diff --cc gcc/fortran/trans-expr.c index bb5cfad,62ba932..8d81f2b --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@@ -39,9 -39,8 +39,8 @@@ along with GCC; see the file COPYING3 /* Only for gfc_trans_assign and gfc_trans_pointer_assign. */ #include "trans-stmt.h" #include "dependency.h" - #include "gimple.h" #include "gimplify.h" - +#include "wide-int.h" /* Convert a scalar to an array descriptor. To be used for assumed-rank arrays. */ diff --cc gcc/gengtype.c index 0c0195c,ca7ce4d..3368433 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@@ -1765,9 -1766,12 +1765,12 @@@ open_base_files (void static const char *const ifiles[] = { "config.h", "system.h", "coretypes.h", "tm.h", "hashtab.h", "splay-tree.h", "obstack.h", "bitmap.h", "input.h", - "tree.h", "rtl.h", "function.h", "insn-config.h", "expr.h", + "tree.h", "rtl.h", "wide-int.h", "function.h", "insn-config.h", "expr.h", "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h", "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h", + "pointer-set.h", "hash-table.h", "vec.h", "ggc.h", "basic-block.h", + "tree-ssa-alias.h", "internal-fn.h", "gimple-fold.h", "tree-eh.h", + "gimple-expr.h", "is-a.h", "gimple.h", "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h", "tree-phinodes.h", "ssa-iterators.h", "stringpool.h", "tree-ssanames.h", "tree-ssa-loop.h", "tree-ssa-loop-ivopts.h", "tree-ssa-loop-manip.h", diff --cc gcc/gimple-ssa-strength-reduction.c index 516756f,8471812..6dbb36c --- a/gcc/gimple-ssa-strength-reduction.c +++ b/gcc/gimple-ssa-strength-reduction.c @@@ -53,12 -59,10 +59,11 @@@ along with GCC; see the file COPYING3 #include "stringpool.h" #include "tree-ssanames.h" #include "domwalk.h" - #include "pointer-set.h" #include "expmed.h" #include "params.h" - #include "hash-table.h" #include "tree-ssa-address.h" + #include "tree-affine.h" +#include "wide-int-print.h" /* Information about a strength reduction candidate. Each statement in the candidate table represents an expression of one of the @@@ -426,6 -430,42 +431,42 @@@ cand_chain_hasher::equal (const value_t /* Hash table embodying a mapping from base exprs to chains of candidates. */ static hash_table base_cand_map; + /* Pointer map used by tree_to_aff_combination_expand. */ + static struct pointer_map_t *name_expansions; + /* Pointer map embodying a mapping from bases to alternative bases. */ + static struct pointer_map_t *alt_base_map; + + /* Given BASE, use the tree affine combiniation facilities to + find the underlying tree expression for BASE, with any + immediate offset excluded. */ + + static tree + get_alternative_base (tree base) + { + tree *result = (tree *) pointer_map_contains (alt_base_map, base); + + if (result == NULL) + { + tree expr; + aff_tree aff; + + tree_to_aff_combination_expand (base, TREE_TYPE (base), + &aff, &name_expansions); - aff.offset = tree_to_double_int (integer_zero_node); ++ aff.offset = 0; + expr = aff_combination_to_tree (&aff); + + result = (tree *) pointer_map_insert (alt_base_map, base); + gcc_assert (!*result); + + if (expr == base) + *result = NULL; + else + *result = expr; + } + + return *result; + } + /* Look in the candidate table for a CAND_PHI that defines BASE and return it if found; otherwise return NULL. */ @@@ -560,11 -612,19 +613,19 @@@ record_potential_basis (slsr_cand_t c, } /* Allocate storage for a new candidate and initialize its fields. - Attempt to find a basis for the candidate. */ + Attempt to find a basis for the candidate. + + For CAND_REF, an alternative base may also be recorded and used + to find a basis. This helps cases where the expression hidden + behind BASE (which is usually an SSA_NAME) has immediate offset, + e.g. + + a2[i][j] = 1; + a2[i + 20][j] = 2; */ static slsr_cand_t - alloc_cand_and_find_basis (enum cand_kind kind, gimple gs, tree base, + alloc_cand_and_find_basis (enum cand_kind kind, gimple gs, tree base, - double_int index, tree stride, tree ctype, + const widest_int &index, tree stride, tree ctype, unsigned savings) { slsr_cand_t c = (slsr_cand_t) obstack_alloc (&cand_obstack, diff --cc gcc/ipa-prop.c index 3953442,712dab7..acc01fc --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@@ -3757,6 -3766,124 +3765,124 @@@ ipa_modify_call_arguments (struct cgrap free_dominance_info (CDI_DOMINATORS); } + /* If the expression *EXPR should be replaced by a reduction of a parameter, do + so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT + specifies whether the function should care about type incompatibility the + current and new expressions. If it is false, the function will leave + incompatibility issues to the caller. Return true iff the expression + was modified. */ + + bool + ipa_modify_expr (tree *expr, bool convert, + ipa_parm_adjustment_vec adjustments) + { + struct ipa_parm_adjustment *cand + = ipa_get_adjustment_candidate (&expr, &convert, adjustments, false); + if (!cand) + return false; + + tree src; + if (cand->by_ref) + src = build_simple_mem_ref (cand->new_decl); + else + src = cand->new_decl; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "About to replace expr "); + print_generic_expr (dump_file, *expr, 0); + fprintf (dump_file, " with "); + print_generic_expr (dump_file, src, 0); + fprintf (dump_file, "\n"); + } + + if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type)) + { + tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src); + *expr = vce; + } + else + *expr = src; + return true; + } + + /* If T is an SSA_NAME, return NULL if it is not a default def or + return its base variable if it is. If IGNORE_DEFAULT_DEF is true, + the base variable is always returned, regardless if it is a default + def. Return T if it is not an SSA_NAME. */ + + static tree + get_ssa_base_param (tree t, bool ignore_default_def) + { + if (TREE_CODE (t) == SSA_NAME) + { + if (ignore_default_def || SSA_NAME_IS_DEFAULT_DEF (t)) + return SSA_NAME_VAR (t); + else + return NULL_TREE; + } + return t; + } + + /* Given an expression, return an adjustment entry specifying the + transformation to be done on EXPR. If no suitable adjustment entry + was found, returns NULL. + + If IGNORE_DEFAULT_DEF is set, consider SSA_NAMEs which are not a + default def, otherwise bail on them. + + If CONVERT is non-NULL, this function will set *CONVERT if the + expression provided is a component reference. ADJUSTMENTS is the + adjustments vector. */ + + ipa_parm_adjustment * + ipa_get_adjustment_candidate (tree **expr, bool *convert, + ipa_parm_adjustment_vec adjustments, + bool ignore_default_def) + { + if (TREE_CODE (**expr) == BIT_FIELD_REF + || TREE_CODE (**expr) == IMAGPART_EXPR + || TREE_CODE (**expr) == REALPART_EXPR) + { + *expr = &TREE_OPERAND (**expr, 0); + if (convert) + *convert = true; + } + + HOST_WIDE_INT offset, size, max_size; + tree base = get_ref_base_and_extent (**expr, &offset, &size, &max_size); + if (!base || size == -1 || max_size == -1) + return NULL; + + if (TREE_CODE (base) == MEM_REF) + { - offset += mem_ref_offset (base).low * BITS_PER_UNIT; ++ offset += mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT; + base = TREE_OPERAND (base, 0); + } + + base = get_ssa_base_param (base, ignore_default_def); + if (!base || TREE_CODE (base) != PARM_DECL) + return NULL; + + struct ipa_parm_adjustment *cand = NULL; + unsigned int len = adjustments.length (); + for (unsigned i = 0; i < len; i++) + { + struct ipa_parm_adjustment *adj = &adjustments[i]; + + if (adj->base == base + && (adj->offset == offset || adj->op == IPA_PARM_OP_REMOVE)) + { + cand = adj; + break; + } + } + + if (!cand || cand->op == IPA_PARM_OP_COPY || cand->op == IPA_PARM_OP_REMOVE) + return NULL; + return cand; + } + /* Return true iff BASE_INDEX is in ADJUSTMENTS more than once. */ static bool diff --cc gcc/lto-streamer-in.c index f2a3c0f,c5cb23c..3fbe820 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@@ -714,16 -711,15 +717,21 @@@ input_cfg (struct lto_input_block *ib, loop->any_estimate = streamer_read_hwi (ib); if (loop->any_estimate) { - loop->nb_iterations_estimate.low = streamer_read_uhwi (ib); - loop->nb_iterations_estimate.high = streamer_read_hwi (ib); + HOST_WIDE_INT a[WIDE_INT_MAX_ELTS]; + int i; + int prec ATTRIBUTE_UNUSED = streamer_read_uhwi (ib); + int len = streamer_read_uhwi (ib); + for (i = 0; i < len; i++) + a[i] = streamer_read_hwi (ib); + + loop->nb_iterations_estimate = widest_int::from_array (a, len); } + /* Read OMP SIMD related info. */ + loop->safelen = streamer_read_hwi (ib); + loop->force_vect = streamer_read_hwi (ib); + loop->simduid = stream_read_tree (ib, data_in); + place_new_loop (fn, loop); /* flow_loops_find doesn't like loops not in the tree, hook them diff --cc gcc/lto-streamer-out.c index a06f386,3135f00..6b78f4b --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@@ -1645,14 -1681,14 +1689,19 @@@ output_cfg (struct output_block *ob, st streamer_write_hwi (ob, loop->any_estimate); if (loop->any_estimate) { - streamer_write_uhwi (ob, loop->nb_iterations_estimate.low); - streamer_write_hwi (ob, loop->nb_iterations_estimate.high); + int len = loop->nb_iterations_estimate.get_len (); + int i; + + streamer_write_uhwi (ob, loop->nb_iterations_estimate.get_precision ()); + streamer_write_uhwi (ob, len); + for (i = 0; i < len; i++) + streamer_write_hwi (ob, loop->nb_iterations_estimate.elt (i)); } + + /* Write OMP SIMD related info. */ + streamer_write_hwi (ob, loop->safelen); + streamer_write_hwi (ob, loop->force_vect); + stream_write_tree (ob, loop->simduid, true); } ob->main_stream = tmp_stream; diff --cc gcc/targhooks.h index aed5778,c24db16..0d8a30e --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@@ -206,13 -206,5 +206,6 @@@ extern bool default_member_type_forces_ extern void default_atomic_assign_expand_fenv (tree *, tree *, tree *); extern tree build_va_arg_indirect_ref (tree); extern tree std_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); - - extern rtx default_load_bounds_for_arg (rtx, rtx, rtx); - extern void default_store_bounds_for_arg (rtx, rtx, rtx, rtx); - extern tree default_fn_abi_va_list_bounds_size (tree); - extern tree default_chkp_bound_type (void); - extern enum machine_mode default_chkp_bound_mode (void); - extern tree default_builtin_chkp_function (unsigned int); -extern bool can_use_doloop_if_innermost (double_int, double_int, +extern bool can_use_doloop_if_innermost (const widest_int &, + const widest_int &, unsigned int, bool); diff --cc gcc/tree-dfa.h index ab7dd19,71f2c21..13811a0 --- a/gcc/tree-dfa.h +++ b/gcc/tree-dfa.h @@@ -102,11 -102,11 +102,10 @@@ get_addr_base_and_unit_offset_1 (tree e && (unit_size = array_ref_element_size (exp), TREE_CODE (unit_size) == INTEGER_CST)) { - HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index); - - hindex -= TREE_INT_CST_LOW (low_bound); - hindex *= TREE_INT_CST_LOW (unit_size); - byte_offset += hindex; - double_int doffset - = (TREE_INT_CST (index) - TREE_INT_CST (low_bound)) - .sext (TYPE_PRECISION (TREE_TYPE (index))); - doffset *= tree_to_double_int (unit_size); - byte_offset += doffset.to_shwi (); ++ offset_int woffset ++ = offset_int::from (wi::sub (index, low_bound), SIGNED); ++ woffset *= wi::to_offset (unit_size); ++ byte_offset += woffset.to_shwi (); } else return NULL_TREE; diff --cc gcc/tree-ssa-ccp.c index acd7fa1,3d05258..473ee92 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@@ -146,8 -144,6 +153,7 @@@ along with GCC; see the file COPYING3 #include "diagnostic-core.h" #include "dbgcnt.h" #include "params.h" - #include "hash-table.h" +#include "wide-int-print.h" /* Possible lattice values. */ diff --cc gcc/tree-streamer-out.c index c7dca47,b86092a..c1dab14 --- a/gcc/tree-streamer-out.c +++ b/gcc/tree-streamer-out.c @@@ -961,12 -1032,8 +1035,14 @@@ streamer_write_tree_header (struct outp streamer_write_uhwi (ob, BINFO_N_BASE_BINFOS (expr)); else if (TREE_CODE (expr) == CALL_EXPR) streamer_write_uhwi (ob, call_expr_nargs (expr)); + else if (TREE_CODE (expr) == OMP_CLAUSE) + streamer_write_uhwi (ob, OMP_CLAUSE_CODE (expr)); + else if (CODE_CONTAINS_STRUCT (code, TS_INT_CST)) + { + gcc_checking_assert (TREE_INT_CST_NUNITS (expr)); + streamer_write_uhwi (ob, TREE_INT_CST_NUNITS (expr)); + streamer_write_uhwi (ob, TREE_INT_CST_EXT_NUNITS (expr)); + } } diff --cc gcc/tree-vect-stmts.c index 1aede48,ff7b59a..5d0ccb6 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@@ -2105,6 -2108,605 +2108,603 @@@ vectorizable_call (gimple stmt, gimple_ } + struct simd_call_arg_info + { + tree vectype; + tree op; + enum vect_def_type dt; + HOST_WIDE_INT linear_step; + unsigned int align; + }; + + /* Function vectorizable_simd_clone_call. + + Check if STMT performs a function call that can be vectorized + by calling a simd clone of the function. + If VEC_STMT is also passed, vectorize the STMT: create a vectorized + stmt to replace it, put it in VEC_STMT, and insert it at BSI. + Return FALSE if not a vectorizable STMT, TRUE otherwise. */ + + static bool + vectorizable_simd_clone_call (gimple stmt, gimple_stmt_iterator *gsi, + gimple *vec_stmt, slp_tree slp_node) + { + tree vec_dest; + tree scalar_dest; + tree op, type; + tree vec_oprnd0 = NULL_TREE; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt), prev_stmt_info; + tree vectype; + unsigned int nunits; + loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); + bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info); + struct loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL; + tree fndecl, new_temp, def; + gimple def_stmt; + gimple new_stmt = NULL; + int ncopies, j; + vec arginfo = vNULL; + vec vargs = vNULL; + size_t i, nargs; + tree lhs, rtype, ratype; + vec *ret_ctor_elts; + + /* Is STMT a vectorizable call? */ + if (!is_gimple_call (stmt)) + return false; + + fndecl = gimple_call_fndecl (stmt); + if (fndecl == NULL_TREE) + return false; + + struct cgraph_node *node = cgraph_get_node (fndecl); + if (node == NULL || node->simd_clones == NULL) + return false; + + if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo) + return false; + + if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def) + return false; + + if (gimple_call_lhs (stmt) + && TREE_CODE (gimple_call_lhs (stmt)) != SSA_NAME) + return false; + + gcc_checking_assert (!stmt_can_throw_internal (stmt)); + + vectype = STMT_VINFO_VECTYPE (stmt_info); + + if (loop_vinfo && nested_in_vect_loop_p (loop, stmt)) + return false; + + /* FORNOW */ + if (slp_node || PURE_SLP_STMT (stmt_info)) + return false; + + /* Process function arguments. */ + nargs = gimple_call_num_args (stmt); + + /* Bail out if the function has zero arguments. */ + if (nargs == 0) + return false; + + arginfo.create (nargs); + + for (i = 0; i < nargs; i++) + { + simd_call_arg_info thisarginfo; + affine_iv iv; + + thisarginfo.linear_step = 0; + thisarginfo.align = 0; + thisarginfo.op = NULL_TREE; + + op = gimple_call_arg (stmt, i); + if (!vect_is_simple_use_1 (op, stmt, loop_vinfo, bb_vinfo, + &def_stmt, &def, &thisarginfo.dt, + &thisarginfo.vectype) + || thisarginfo.dt == vect_uninitialized_def) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "use not simple.\n"); + arginfo.release (); + return false; + } + + if (thisarginfo.dt == vect_constant_def + || thisarginfo.dt == vect_external_def) + gcc_assert (thisarginfo.vectype == NULL_TREE); + else + gcc_assert (thisarginfo.vectype != NULL_TREE); + + if (thisarginfo.dt != vect_constant_def + && thisarginfo.dt != vect_external_def + && loop_vinfo + && TREE_CODE (op) == SSA_NAME + && simple_iv (loop, loop_containing_stmt (stmt), op, &iv, false) + && tree_fits_shwi_p (iv.step)) + { + thisarginfo.linear_step = tree_to_shwi (iv.step); + thisarginfo.op = iv.base; + } + else if ((thisarginfo.dt == vect_constant_def + || thisarginfo.dt == vect_external_def) + && POINTER_TYPE_P (TREE_TYPE (op))) + thisarginfo.align = get_pointer_alignment (op) / BITS_PER_UNIT; + + arginfo.quick_push (thisarginfo); + } + + unsigned int badness = 0; + struct cgraph_node *bestn = NULL; + if (STMT_VINFO_SIMD_CLONE_FNDECL (stmt_info)) + bestn = cgraph_get_node (STMT_VINFO_SIMD_CLONE_FNDECL (stmt_info)); + else + for (struct cgraph_node *n = node->simd_clones; n != NULL; + n = n->simdclone->next_clone) + { + unsigned int this_badness = 0; + if (n->simdclone->simdlen + > (unsigned) LOOP_VINFO_VECT_FACTOR (loop_vinfo) + || n->simdclone->nargs != nargs) + continue; + if (n->simdclone->simdlen + < (unsigned) LOOP_VINFO_VECT_FACTOR (loop_vinfo)) + this_badness += (exact_log2 (LOOP_VINFO_VECT_FACTOR (loop_vinfo)) + - exact_log2 (n->simdclone->simdlen)) * 1024; + if (n->simdclone->inbranch) + this_badness += 2048; + int target_badness = targetm.simd_clone.usable (n); + if (target_badness < 0) + continue; + this_badness += target_badness * 512; + /* FORNOW: Have to add code to add the mask argument. */ + if (n->simdclone->inbranch) + continue; + for (i = 0; i < nargs; i++) + { + switch (n->simdclone->args[i].arg_type) + { + case SIMD_CLONE_ARG_TYPE_VECTOR: + if (!useless_type_conversion_p + (n->simdclone->args[i].orig_type, + TREE_TYPE (gimple_call_arg (stmt, i)))) + i = -1; + else if (arginfo[i].dt == vect_constant_def + || arginfo[i].dt == vect_external_def + || arginfo[i].linear_step) + this_badness += 64; + break; + case SIMD_CLONE_ARG_TYPE_UNIFORM: + if (arginfo[i].dt != vect_constant_def + && arginfo[i].dt != vect_external_def) + i = -1; + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: + if (arginfo[i].dt == vect_constant_def + || arginfo[i].dt == vect_external_def + || (arginfo[i].linear_step + != n->simdclone->args[i].linear_step)) + i = -1; + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: + /* FORNOW */ + i = -1; + break; + case SIMD_CLONE_ARG_TYPE_MASK: + gcc_unreachable (); + } + if (i == (size_t) -1) + break; + if (n->simdclone->args[i].alignment > arginfo[i].align) + { + i = -1; + break; + } + if (arginfo[i].align) + this_badness += (exact_log2 (arginfo[i].align) + - exact_log2 (n->simdclone->args[i].alignment)); + } + if (i == (size_t) -1) + continue; + if (bestn == NULL || this_badness < badness) + { + bestn = n; + badness = this_badness; + } + } + + if (bestn == NULL) + { + arginfo.release (); + return false; + } + + for (i = 0; i < nargs; i++) + if ((arginfo[i].dt == vect_constant_def + || arginfo[i].dt == vect_external_def) + && bestn->simdclone->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR) + { + arginfo[i].vectype + = get_vectype_for_scalar_type (TREE_TYPE (gimple_call_arg (stmt, + i))); + if (arginfo[i].vectype == NULL + || (TYPE_VECTOR_SUBPARTS (arginfo[i].vectype) + > bestn->simdclone->simdlen)) + { + arginfo.release (); + return false; + } + } + + fndecl = bestn->decl; + nunits = bestn->simdclone->simdlen; + ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits; + + /* If the function isn't const, only allow it in simd loops where user + has asserted that at least nunits consecutive iterations can be + performed using SIMD instructions. */ + if ((loop == NULL || (unsigned) loop->safelen < nunits) + && gimple_vuse (stmt)) + { + arginfo.release (); + return false; + } + + /* Sanity check: make sure that at least one copy of the vectorized stmt + needs to be generated. */ + gcc_assert (ncopies >= 1); + + if (!vec_stmt) /* transformation not required. */ + { + STMT_VINFO_SIMD_CLONE_FNDECL (stmt_info) = bestn->decl; + STMT_VINFO_TYPE (stmt_info) = call_simd_clone_vec_info_type; + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "=== vectorizable_simd_clone_call ===\n"); + /* vect_model_simple_cost (stmt_info, ncopies, dt, NULL, NULL); */ + arginfo.release (); + return true; + } + + /** Transform. **/ + + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, "transform call.\n"); + + /* Handle def. */ + scalar_dest = gimple_call_lhs (stmt); + vec_dest = NULL_TREE; + rtype = NULL_TREE; + ratype = NULL_TREE; + if (scalar_dest) + { + vec_dest = vect_create_destination_var (scalar_dest, vectype); + rtype = TREE_TYPE (TREE_TYPE (fndecl)); + if (TREE_CODE (rtype) == ARRAY_TYPE) + { + ratype = rtype; + rtype = TREE_TYPE (ratype); + } + } + + prev_stmt_info = NULL; + for (j = 0; j < ncopies; ++j) + { + /* Build argument list for the vectorized call. */ + if (j == 0) + vargs.create (nargs); + else + vargs.truncate (0); + + for (i = 0; i < nargs; i++) + { + unsigned int k, l, m, o; + tree atype; + op = gimple_call_arg (stmt, i); + switch (bestn->simdclone->args[i].arg_type) + { + case SIMD_CLONE_ARG_TYPE_VECTOR: + atype = bestn->simdclone->args[i].vector_type; + o = nunits / TYPE_VECTOR_SUBPARTS (atype); + for (m = j * o; m < (j + 1) * o; m++) + { + if (TYPE_VECTOR_SUBPARTS (atype) + < TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)) + { + unsigned int prec = GET_MODE_BITSIZE (TYPE_MODE (atype)); + k = (TYPE_VECTOR_SUBPARTS (arginfo[i].vectype) + / TYPE_VECTOR_SUBPARTS (atype)); + gcc_assert ((k & (k - 1)) == 0); + if (m == 0) + vec_oprnd0 + = vect_get_vec_def_for_operand (op, stmt, NULL); + else + { + vec_oprnd0 = arginfo[i].op; + if ((m & (k - 1)) == 0) + vec_oprnd0 + = vect_get_vec_def_for_stmt_copy (arginfo[i].dt, + vec_oprnd0); + } + arginfo[i].op = vec_oprnd0; + vec_oprnd0 + = build3 (BIT_FIELD_REF, atype, vec_oprnd0, + size_int (prec), + bitsize_int ((m & (k - 1)) * prec)); + new_stmt + = gimple_build_assign (make_ssa_name (atype, NULL), + vec_oprnd0); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + vargs.safe_push (gimple_assign_lhs (new_stmt)); + } + else + { + k = (TYPE_VECTOR_SUBPARTS (atype) + / TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)); + gcc_assert ((k & (k - 1)) == 0); + vec *ctor_elts; + if (k != 1) + vec_alloc (ctor_elts, k); + else + ctor_elts = NULL; + for (l = 0; l < k; l++) + { + if (m == 0 && l == 0) + vec_oprnd0 + = vect_get_vec_def_for_operand (op, stmt, NULL); + else + vec_oprnd0 + = vect_get_vec_def_for_stmt_copy (arginfo[i].dt, + arginfo[i].op); + arginfo[i].op = vec_oprnd0; + if (k == 1) + break; + CONSTRUCTOR_APPEND_ELT (ctor_elts, NULL_TREE, + vec_oprnd0); + } + if (k == 1) + vargs.safe_push (vec_oprnd0); + else + { + vec_oprnd0 = build_constructor (atype, ctor_elts); + new_stmt + = gimple_build_assign (make_ssa_name (atype, NULL), + vec_oprnd0); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + vargs.safe_push (gimple_assign_lhs (new_stmt)); + } + } + } + break; + case SIMD_CLONE_ARG_TYPE_UNIFORM: + vargs.safe_push (op); + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP: + if (j == 0) + { + gimple_seq stmts; + arginfo[i].op + = force_gimple_operand (arginfo[i].op, &stmts, true, + NULL_TREE); + if (stmts != NULL) + { + basic_block new_bb; + edge pe = loop_preheader_edge (loop); + new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts); + gcc_assert (!new_bb); + } + tree phi_res = copy_ssa_name (op, NULL); + gimple new_phi = create_phi_node (phi_res, loop->header); + set_vinfo_for_stmt (new_phi, + new_stmt_vec_info (new_phi, loop_vinfo, + NULL)); + add_phi_arg (new_phi, arginfo[i].op, + loop_preheader_edge (loop), UNKNOWN_LOCATION); + enum tree_code code + = POINTER_TYPE_P (TREE_TYPE (op)) + ? POINTER_PLUS_EXPR : PLUS_EXPR; + tree type = POINTER_TYPE_P (TREE_TYPE (op)) + ? sizetype : TREE_TYPE (op); - double_int cst - = double_int::from_shwi - (bestn->simdclone->args[i].linear_step); - cst *= double_int::from_uhwi (ncopies * nunits); - tree tcst = double_int_to_tree (type, cst); ++ widest_int cst ++ = wi::mul (bestn->simdclone->args[i].linear_step, ++ ncopies * nunits); ++ tree tcst = wide_int_to_tree (type, cst); + tree phi_arg = copy_ssa_name (op, NULL); + new_stmt = gimple_build_assign_with_ops (code, phi_arg, + phi_res, tcst); + gimple_stmt_iterator si = gsi_after_labels (loop->header); + gsi_insert_after (&si, new_stmt, GSI_NEW_STMT); + set_vinfo_for_stmt (new_stmt, + new_stmt_vec_info (new_stmt, loop_vinfo, + NULL)); + add_phi_arg (new_phi, phi_arg, loop_latch_edge (loop), + UNKNOWN_LOCATION); + arginfo[i].op = phi_res; + vargs.safe_push (phi_res); + } + else + { + enum tree_code code + = POINTER_TYPE_P (TREE_TYPE (op)) + ? POINTER_PLUS_EXPR : PLUS_EXPR; + tree type = POINTER_TYPE_P (TREE_TYPE (op)) + ? sizetype : TREE_TYPE (op); - double_int cst - = double_int::from_shwi - (bestn->simdclone->args[i].linear_step); - cst *= double_int::from_uhwi (j * nunits); - tree tcst = double_int_to_tree (type, cst); ++ widest_int cst ++ = wi::mul (bestn->simdclone->args[i].linear_step, ++ j * nunits); ++ tree tcst = wide_int_to_tree (type, cst); + new_temp = make_ssa_name (TREE_TYPE (op), NULL); + new_stmt + = gimple_build_assign_with_ops (code, new_temp, + arginfo[i].op, tcst); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + vargs.safe_push (new_temp); + } + break; + case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP: + default: + gcc_unreachable (); + } + } + + new_stmt = gimple_build_call_vec (fndecl, vargs); + if (vec_dest) + { + gcc_assert (ratype || TYPE_VECTOR_SUBPARTS (rtype) == nunits); + if (ratype) + new_temp = create_tmp_var (ratype, NULL); + else if (TYPE_VECTOR_SUBPARTS (vectype) + == TYPE_VECTOR_SUBPARTS (rtype)) + new_temp = make_ssa_name (vec_dest, new_stmt); + else + new_temp = make_ssa_name (rtype, new_stmt); + gimple_call_set_lhs (new_stmt, new_temp); + } + vect_finish_stmt_generation (stmt, new_stmt, gsi); + + if (vec_dest) + { + if (TYPE_VECTOR_SUBPARTS (vectype) < nunits) + { + unsigned int k, l; + unsigned int prec = GET_MODE_BITSIZE (TYPE_MODE (vectype)); + k = nunits / TYPE_VECTOR_SUBPARTS (vectype); + gcc_assert ((k & (k - 1)) == 0); + for (l = 0; l < k; l++) + { + tree t; + if (ratype) + { + t = build_fold_addr_expr (new_temp); + t = build2 (MEM_REF, vectype, t, + build_int_cst (TREE_TYPE (t), + l * prec / BITS_PER_UNIT)); + } + else + t = build3 (BIT_FIELD_REF, vectype, new_temp, + size_int (prec), bitsize_int (l * prec)); + new_stmt + = gimple_build_assign (make_ssa_name (vectype, NULL), t); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + if (j == 0 && l == 0) + STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt; + else + STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt; + + prev_stmt_info = vinfo_for_stmt (new_stmt); + } + + if (ratype) + { + tree clobber = build_constructor (ratype, NULL); + TREE_THIS_VOLATILE (clobber) = 1; + new_stmt = gimple_build_assign (new_temp, clobber); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + } + continue; + } + else if (TYPE_VECTOR_SUBPARTS (vectype) > nunits) + { + unsigned int k = (TYPE_VECTOR_SUBPARTS (vectype) + / TYPE_VECTOR_SUBPARTS (rtype)); + gcc_assert ((k & (k - 1)) == 0); + if ((j & (k - 1)) == 0) + vec_alloc (ret_ctor_elts, k); + if (ratype) + { + unsigned int m, o = nunits / TYPE_VECTOR_SUBPARTS (rtype); + for (m = 0; m < o; m++) + { + tree tem = build4 (ARRAY_REF, rtype, new_temp, + size_int (m), NULL_TREE, NULL_TREE); + new_stmt + = gimple_build_assign (make_ssa_name (rtype, NULL), + tem); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, + gimple_assign_lhs (new_stmt)); + } + tree clobber = build_constructor (ratype, NULL); + TREE_THIS_VOLATILE (clobber) = 1; + new_stmt = gimple_build_assign (new_temp, clobber); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + } + else + CONSTRUCTOR_APPEND_ELT (ret_ctor_elts, NULL_TREE, new_temp); + if ((j & (k - 1)) != k - 1) + continue; + vec_oprnd0 = build_constructor (vectype, ret_ctor_elts); + new_stmt + = gimple_build_assign (make_ssa_name (vec_dest, NULL), + vec_oprnd0); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + + if ((unsigned) j == k - 1) + STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt; + else + STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt; + + prev_stmt_info = vinfo_for_stmt (new_stmt); + continue; + } + else if (ratype) + { + tree t = build_fold_addr_expr (new_temp); + t = build2 (MEM_REF, vectype, t, + build_int_cst (TREE_TYPE (t), 0)); + new_stmt + = gimple_build_assign (make_ssa_name (vec_dest, NULL), t); + vect_finish_stmt_generation (stmt, new_stmt, gsi); + tree clobber = build_constructor (ratype, NULL); + TREE_THIS_VOLATILE (clobber) = 1; + vect_finish_stmt_generation (stmt, + gimple_build_assign (new_temp, + clobber), gsi); + } + } + + if (j == 0) + STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt; + else + STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt; + + prev_stmt_info = vinfo_for_stmt (new_stmt); + } + + vargs.release (); + + /* The call in STMT might prevent it from being removed in dce. + We however cannot remove it here, due to the way the ssa name + it defines is mapped to the new definition. So just replace + rhs of the statement with something harmless. */ + + if (slp_node) + return true; + + if (scalar_dest) + { + type = TREE_TYPE (scalar_dest); + if (is_pattern_stmt_p (stmt_info)) + lhs = gimple_call_lhs (STMT_VINFO_RELATED_STMT (stmt_info)); + else + lhs = gimple_call_lhs (stmt); + new_stmt = gimple_build_assign (lhs, build_zero_cst (type)); + } + else + new_stmt = gimple_build_nop (); + set_vinfo_for_stmt (new_stmt, stmt_info); + set_vinfo_for_stmt (stmt, NULL); + STMT_VINFO_STMT (stmt_info) = new_stmt; + gsi_replace (gsi, new_stmt, false); + unlink_stmt_vdef (stmt); + + return true; + } + + /* Function vect_gen_widened_results_half Create a vector stmt whose code, type, number of arguments, and result diff --cc gcc/tree.c index 0196a32,0967b43..9912899 --- a/gcc/tree.c +++ b/gcc/tree.c @@@ -1197,103 -1147,73 +1200,102 @@@ wide_int_to_tree (tree type, const wide int limit = 0; gcc_assert (type); + unsigned int prec = TYPE_PRECISION (type); + signop sgn = TYPE_SIGN (type); - switch (TREE_CODE (type)) + /* Verify that everything is canonical. */ + int l = pcst.get_len (); + if (l > 1) { - case NULLPTR_TYPE: - gcc_assert (hi == 0 && low == 0); - /* Fallthru. */ - - case POINTER_TYPE: - case REFERENCE_TYPE: - /* Cache NULL pointer. */ - if (!hi && !low) - { - limit = 1; - ix = 0; - } - break; + if (pcst.elt (l - 1) == 0) + gcc_checking_assert (pcst.elt (l - 2) < 0); + if (pcst.elt (l - 1) == (HOST_WIDE_INT) -1) + gcc_checking_assert (pcst.elt (l - 2) >= 0); + } - case BOOLEAN_TYPE: - /* Cache false or true. */ - limit = 2; - if (!hi && low < 2) - ix = low; - break; + wide_int cst = wide_int::from (pcst, prec, sgn); + unsigned int ext_len = get_int_cst_ext_nunits (type, cst); - case INTEGER_TYPE: - case OFFSET_TYPE: + if (ext_len == 1) + { + /* We just need to store a single HOST_WIDE_INT. */ + HOST_WIDE_INT hwi; if (TYPE_UNSIGNED (type)) - { - /* Cache 0..N */ - limit = INTEGER_SHARE_LIMIT; - if (!hi && low < (unsigned HOST_WIDE_INT)INTEGER_SHARE_LIMIT) - ix = low; - } + hwi = cst.to_uhwi (); else + hwi = cst.to_shwi (); + + switch (TREE_CODE (type)) { - /* Cache -1..N */ - limit = INTEGER_SHARE_LIMIT + 1; - if (!hi && low < (unsigned HOST_WIDE_INT)INTEGER_SHARE_LIMIT) - ix = low + 1; - else if (hi == -1 && low == -(unsigned HOST_WIDE_INT)1) - ix = 0; - } - break; + case NULLPTR_TYPE: + gcc_assert (hwi == 0); + /* Fallthru. */ + + case POINTER_TYPE: + case REFERENCE_TYPE: - case POINTER_BOUNDS_TYPE: - /* Cache NULL pointer and zero bounds. */ ++ /* Cache NULL pointer. */ + if (hwi == 0) + { + limit = 1; + ix = 0; + } + break; - case ENUMERAL_TYPE: - break; + case BOOLEAN_TYPE: + /* Cache false or true. */ + limit = 2; + if (hwi < 2) + ix = hwi; + break; - default: - gcc_unreachable (); - } + case INTEGER_TYPE: + case OFFSET_TYPE: + if (TYPE_SIGN (type) == UNSIGNED) + { + /* Cache [0, N). */ + limit = INTEGER_SHARE_LIMIT; + if (IN_RANGE (hwi, 0, INTEGER_SHARE_LIMIT - 1)) + ix = hwi; + } + else + { + /* Cache [-1, N). */ + limit = INTEGER_SHARE_LIMIT + 1; + if (IN_RANGE (hwi, -1, INTEGER_SHARE_LIMIT - 1)) + ix = hwi + 1; + } + break; - if (ix >= 0) - { - /* Look for it in the type's vector of small shared ints. */ - if (!TYPE_CACHED_VALUES_P (type)) - { - TYPE_CACHED_VALUES_P (type) = 1; - TYPE_CACHED_VALUES (type) = make_tree_vec (limit); + case ENUMERAL_TYPE: + break; + + default: + gcc_unreachable (); } - t = TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix); - if (t) + if (ix >= 0) { - /* Make sure no one is clobbering the shared constant. */ - gcc_assert (TREE_TYPE (t) == type); - gcc_assert (TREE_INT_CST_LOW (t) == low); - gcc_assert (TREE_INT_CST_HIGH (t) == hi); + /* Look for it in the type's vector of small shared ints. */ + if (!TYPE_CACHED_VALUES_P (type)) + { + TYPE_CACHED_VALUES_P (type) = 1; + TYPE_CACHED_VALUES (type) = make_tree_vec (limit); + } + + t = TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix); + if (t) + /* Make sure no one is clobbering the shared constant. */ + gcc_checking_assert (TREE_TYPE (t) == type + && TREE_INT_CST_NUNITS (t) == 1 + && TREE_INT_CST_OFFSET_NUNITS (t) == 1 + && TREE_INT_CST_EXT_NUNITS (t) == 1 + && TREE_INT_CST_ELT (t, 0) == hwi); + else + { + /* Create a new shared int. */ + t = build_new_int_cst (type, cst); + TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix) = t; + } } else {