On Thu, Nov 28, 2013 at 12:58 PM, Richard Sandiford
<[email protected]> wrote:
> Jakub Jelinek <[email protected]> writes:
>> On Mon, Nov 25, 2013 at 12:24:30PM +0100, Richard Biener wrote:
>>> On Sat, Nov 23, 2013 at 8:21 PM, Mike Stump <[email protected]> wrote:
>>> > Richi has asked the we break the wide-int patch so that the
>>> > individual port and front end maintainers can review their parts
>>> > without have to go through the entire patch. This patch covers the
>>> > gimple code.
>>>
>>> @@ -1754,7 +1754,7 @@ dump_ssaname_info (pretty_printer *buffer, tree
>>> node, int spc)
>>> if (!POINTER_TYPE_P (TREE_TYPE (node))
>>> && SSA_NAME_RANGE_INFO (node))
>>> {
>>> - double_int min, max, nonzero_bits;
>>> + widest_int min, max, nonzero_bits;
>>> value_range_type range_type = get_range_info (node, &min, &max);
>>>
>>> if (range_type == VR_VARYING)
>>>
>>> this makes me suspect you are changing SSA_NAME_RANGE_INFO
>>> to embed two max wide_ints. That's a no-no.
>>
>> Well, the range_info_def struct right now contains 3 double_ints, which is
>> unnecessary overhead for the most of the cases where the SSA_NAME's type
>> has just at most HOST_BITS_PER_WIDE_INT bits and thus we could fit all 3 of
>> them into 3 HOST_WIDE_INTs rather than 3 double_ints. So supposedly struct
>> range_info_def could be a template on the type's precision rounded up to HWI
>> bits, or say have 3 alternatives there, use
>> FIXED_WIDE_INT (HOST_BITS_PER_WIDE_INT) for the smallest types,
>> FIXED_WIDE_INT (2 * HOST_BITS_PER_WIDE_INT) aka double_int for the larger
>> but still common ones, and widest_int for the rest, then the API to set/get
>> it could use widest_int everywhere, and just what storage we'd use would
>> depend on the precision of the type.
>
> This patch adds a trailing_wide_ints <N> that can be used at the end of
> a variable-length structure to store N wide_ints. There's also a macro
> to declare get/set methods for each of the N elements.
>
> At the moment I've only defined non-const operator[]. It'd be possible
> to add a const version later if necessary.
>
> The size of range_info_def for precisions that fit in M HWIs is then
> 1 + 3 * M, so 4 for the common case (down from 6 on trunk). The maximum
> is 7 for current x86_64 types (up from 6 on trunk).
>
> I wondered whether to keep the interface using widest_int, but I think
> wide_int works out more naturally. The only caller that wants to extend
> beyond the precision is CCP, but that's already special because the upper
> bits are supposed to be set (i.e. it's not a normal sign or zero extension).
>
> This relies on the SSA_NAME_ANTI_RANGE_P patch I just posted.
>
> If this is OK I'll look at using the same structure elsewhere.
Looks good to me.
Thanks,
Richard.
> Thanks,
> Richard
>
>
> Index: gcc/ChangeLog.wide-int
> ===================================================================
> --- gcc/ChangeLog.wide-int 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/ChangeLog.wide-int 2013-11-28 11:37:15.320020047 +0000
> @@ -677,6 +677,7 @@
> * tree-ssa-ccp.c: Update comment at top of file. Include
> wide-int-print.h.
> (struct prop_value_d): Change type of mask to widest_int.
> + (extend_mask): New function.
> (dump_lattice_value): Use wide-int interfaces.
> (get_default_value): Likewise.
> (set_constant_value): Likewise.
> @@ -768,16 +769,20 @@
> * tree-ssa-math-opts.c
> (gimple_expand_builtin_pow): Update calls to real_to_integer.
> * tree-ssanames.c
> - (set_range_info): Use widest_ints rather than double_ints.
> - (get_range_info): Likewise.
> + (set_range_info): Use wide_int_refs rather than double_ints.
> + Adjust for trailing_wide_ints <3> representation.
> (set_nonzero_bits): Likewise.
> + (get_range_info): Return wide_ints rather than double_ints.
> + Adjust for trailing_wide_ints <3> representation.
> (get_nonzero_bits): Likewise.
> + (duplicate_ssa_name_range_info): Adjust for trailing_wide_ints <3>
> + representation.
> * tree-ssanames.h
> - (struct range_info_def): Change type of min, max and nonzero_bits
> - to widest_int.
> - (set_range_info): Use widest_ints rather than double_ints.
> - (get_range_info): Likewise.
> + (struct range_info_def): Replace min, max and nonzero_bits with
> + a trailing_wide_ints <3>.
> + (set_range_info): Use wide_int_refs rather than double_ints.
> (set_nonzero_bits): Likewise.
> + (get_range_info): Return wide_ints rather than double_ints.
> (get_nonzero_bits): Likewise.
> * tree-ssa-phiopt.c
> (jump_function_from_stmt): Use wide-int interfaces.
> Index: gcc/builtins.c
> ===================================================================
> --- gcc/builtins.c 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/builtins.c 2013-11-27 18:45:46.710684576 +0000
> @@ -3125,7 +3125,7 @@ determine_block_size (tree len, rtx len_
> }
> else
> {
> - widest_int min, max;
> + wide_int min, max;
> enum value_range_type range_type = VR_UNDEFINED;
>
> /* Determine bounds from the type. */
> @@ -3152,9 +3152,8 @@ determine_block_size (tree len, rtx len_
> /* Anti range 0...N lets us to determine minmal size to N+1. */
> if (min == 0)
> {
> - widest_int max_plus_one = max + 1;
> - if (wi::fits_uhwi_p (max_plus_one))
> - *min_size = max_plus_one.to_uhwi ();
> + if (wi::fits_uhwi_p (max) && max.to_uhwi () + 1 != 0)
> + *min_size = max.to_uhwi () + 1;
> }
> /* Code like
>
> Index: gcc/gimple-pretty-print.c
> ===================================================================
> --- gcc/gimple-pretty-print.c 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/gimple-pretty-print.c 2013-11-27 18:45:46.706684594 +0000
> @@ -1754,7 +1754,7 @@ dump_ssaname_info (pretty_printer *buffe
> if (!POINTER_TYPE_P (TREE_TYPE (node))
> && SSA_NAME_RANGE_INFO (node))
> {
> - widest_int min, max, nonzero_bits;
> + wide_int min, max, nonzero_bits;
> value_range_type range_type = get_range_info (node, &min, &max);
>
> if (range_type == VR_VARYING)
> @@ -1769,9 +1769,7 @@ dump_ssaname_info (pretty_printer *buffe
> pp_printf (buffer, "]");
> }
> nonzero_bits = get_nonzero_bits (node);
> - if (nonzero_bits != -1
> - && (nonzero_bits
> - != wi::mask <widest_int> (TYPE_PRECISION (TREE_TYPE (node)),
> false)))
> + if (nonzero_bits != -1)
> {
> pp_string (buffer, " NONZERO ");
> pp_wide_int (buffer, nonzero_bits, UNSIGNED);
> Index: gcc/tree-ssa-ccp.c
> ===================================================================
> --- gcc/tree-ssa-ccp.c 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/tree-ssa-ccp.c 2013-11-27 18:45:46.707684590 +0000
> @@ -237,6 +237,14 @@ debug_lattice_value (prop_value_t val)
> fprintf (stderr, "\n");
> }
>
> +/* Extend NONZERO_BITS to a full mask, with the upper bits being set. */
> +
> +static widest_int
> +extend_mask (const wide_int &nonzero_bits)
> +{
> + return (wi::mask <widest_int> (wi::get_precision (nonzero_bits), true)
> + | widest_int::from (nonzero_bits, UNSIGNED));
> +}
>
> /* Compute a default value for variable VAR and store it in the
> CONST_VAL array. The following rules are used to get default
> @@ -279,15 +287,12 @@ get_default_value (tree var)
> val.mask = -1;
> if (flag_tree_bit_ccp)
> {
> - widest_int nonzero_bits = get_nonzero_bits (var);
> - widest_int mask
> - = wi::mask <widest_int> (TYPE_PRECISION (TREE_TYPE (var)),
> false);
> - if (nonzero_bits != -1 && nonzero_bits != mask)
> + wide_int nonzero_bits = get_nonzero_bits (var);
> + if (nonzero_bits != -1)
> {
> val.lattice_val = CONSTANT;
> val.value = build_zero_cst (TREE_TYPE (var));
> - /* CCP wants the bits above precision set. */
> - val.mask = nonzero_bits | ~mask;
> + val.mask = extend_mask (nonzero_bits);
> }
> }
> }
> @@ -895,7 +900,9 @@ ccp_finalize (void)
> }
> else
> {
> - widest_int nonzero_bits = val->mask | wi::to_widest (val->value);
> + unsigned int precision = TYPE_PRECISION (TREE_TYPE (val->value));
> + wide_int nonzero_bits = wide_int::from (val->mask, precision,
> + UNSIGNED) | val->value;
> nonzero_bits &= get_nonzero_bits (name);
> set_nonzero_bits (name, nonzero_bits);
> }
> @@ -1758,29 +1765,25 @@ evaluate_stmt (gimple stmt)
> && TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME)
> {
> tree lhs = gimple_get_lhs (stmt);
> - widest_int nonzero_bits = get_nonzero_bits (lhs);
> - widest_int mask
> - = wi::mask <widest_int> (TYPE_PRECISION (TREE_TYPE (lhs)), false);
> - if (nonzero_bits != -1 && nonzero_bits != mask)
> + wide_int nonzero_bits = get_nonzero_bits (lhs);
> + if (nonzero_bits != -1)
> {
> if (!is_constant)
> {
> val.lattice_val = CONSTANT;
> val.value = build_zero_cst (TREE_TYPE (lhs));
> - /* CCP wants the bits above precision set. */
> - val.mask = nonzero_bits | ~mask;
> + val.mask = extend_mask (nonzero_bits);
> is_constant = true;
> }
> else
> {
> - widest_int valv = wi::to_widest (val.value);
> - if ((valv & ~nonzero_bits & mask) != 0)
> + if (wi::bit_and_not (val.value, nonzero_bits) != 0)
> val.value = wide_int_to_tree (TREE_TYPE (lhs),
> - valv & nonzero_bits);
> + nonzero_bits & val.value);
> if (nonzero_bits == 0)
> val.mask = 0;
> else
> - val.mask = val.mask & (nonzero_bits | ~mask);
> + val.mask = extend_mask (nonzero_bits);
> }
> }
> }
> Index: gcc/tree-ssa-loop-niter.c
> ===================================================================
> --- gcc/tree-ssa-loop-niter.c 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/tree-ssa-loop-niter.c 2013-11-27 18:45:46.711684572 +0000
> @@ -125,7 +125,7 @@ split_to_var_and_offset (tree expr, tree
> determine_value_range (struct loop *loop, tree type, tree var, mpz_t off,
> mpz_t min, mpz_t max)
> {
> - widest_int minv, maxv;
> + wide_int minv, maxv;
> enum value_range_type rtype = VR_VARYING;
>
> /* If the expression is a constant, we know its value exactly. */
> @@ -142,6 +142,7 @@ determine_value_range (struct loop *loop
> if (TREE_CODE (var) == SSA_NAME && INTEGRAL_TYPE_P (type))
> {
> edge e = loop_preheader_edge (loop);
> + signop sgn = TYPE_SIGN (type);
> gimple_stmt_iterator gsi;
>
> /* Either for VAR itself... */
> @@ -151,7 +152,7 @@ determine_value_range (struct loop *loop
> for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next
> (&gsi))
> {
> gimple phi = gsi_stmt (gsi);
> - widest_int minc, maxc;
> + wide_int minc, maxc;
> if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
> && (get_range_info (gimple_phi_result (phi), &minc, &maxc)
> == VR_RANGE))
> @@ -164,20 +165,20 @@ determine_value_range (struct loop *loop
> }
> else
> {
> - minv = wi::smax (minv, minc);
> - maxv = wi::smin (maxv, maxc);
> - gcc_assert (wi::les_p (minv, maxv));
> + minv = wi::max (minv, minc, sgn);
> + maxv = wi::min (maxv, maxc, sgn);
> + gcc_assert (wi::le_p (minv, maxv, sgn));
> }
> }
> }
> if (rtype == VR_RANGE)
> {
> mpz_t minm, maxm;
> - gcc_assert (wi::les_p (minv, maxv));
> + gcc_assert (wi::le_p (minv, maxv, sgn));
> mpz_init (minm);
> mpz_init (maxm);
> - wi::to_mpz (minv, minm, SIGNED);
> - wi::to_mpz (maxv, maxm, SIGNED);
> + wi::to_mpz (minv, minm, sgn);
> + wi::to_mpz (maxv, maxm, sgn);
> mpz_add (minm, minm, off);
> mpz_add (maxm, maxm, off);
> /* If the computation may not wrap or off is zero, then this
> Index: gcc/tree-ssanames.c
> ===================================================================
> --- gcc/tree-ssanames.c 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/tree-ssanames.c 2013-11-27 18:45:46.705684598 +0000
> @@ -182,19 +182,22 @@ make_ssa_name_fn (struct function *fn, t
>
> void
> set_range_info (tree name, enum value_range_type range_type,
> - const widest_int &min, const widest_int &max)
> + const wide_int_ref &min, const wide_int_ref &max)
> {
> gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
> gcc_assert (range_type == VR_RANGE || range_type == VR_ANTI_RANGE);
> range_info_def *ri = SSA_NAME_RANGE_INFO (name);
> + unsigned int precision = TYPE_PRECISION (TREE_TYPE (name));
>
> /* Allocate if not available. */
> if (ri == NULL)
> {
> - ri = ggc_alloc_cleared_range_info_def ();
> + size_t size = (sizeof (range_info_def)
> + + trailing_wide_ints <3>::extra_size (precision));
> + ri = ggc_alloc_range_info_def (size);
> + ri->ints.set_precision (precision);
> SSA_NAME_RANGE_INFO (name) = ri;
> - ri->nonzero_bits = wi::mask <widest_int> (TYPE_PRECISION (TREE_TYPE
> (name)),
> - false);
> + ri->set_nonzero_bits (wi::shwi (-1, precision));
> }
>
> /* Record the range type. */
> @@ -202,22 +205,16 @@ set_range_info (tree name, enum value_ra
> SSA_NAME_ANTI_RANGE_P (name) = (range_type == VR_ANTI_RANGE);
>
> /* Set the values. */
> - ri->min = min;
> - ri->max = max;
> + ri->set_min (min);
> + ri->set_max (max);
>
> /* If it is a range, try to improve nonzero_bits from the min/max. */
> if (range_type == VR_RANGE)
> {
> - int prec = TYPE_PRECISION (TREE_TYPE (name));
> -
> - widest_int ext_min = wi::zext (min, prec);
> - widest_int ext_max = wi::zext (max, prec);
> - widest_int xorv = ext_min ^ ext_max;
> + wide_int xorv = ri->get_min () ^ ri->get_max ();
> if (xorv != 0)
> - xorv = wi::mask <widest_int> (MAX_BITSIZE_MODE_ANY_INT
> - - wi::clz (xorv),
> - false);
> - ri->nonzero_bits = ri->nonzero_bits & (ext_min | xorv);
> + xorv = wi::mask (precision - wi::clz (xorv), false, precision);
> + ri->set_nonzero_bits (ri->get_nonzero_bits () & (ri->get_min () |
> xorv));
> }
> }
>
> @@ -227,7 +224,7 @@ set_range_info (tree name, enum value_ra
> is used to determine if MIN and MAX are valid values. */
>
> enum value_range_type
> -get_range_info (const_tree name, widest_int *min, widest_int *max)
> +get_range_info (const_tree name, wide_int *min, wide_int *max)
> {
> gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
> gcc_assert (min && max);
> @@ -239,52 +236,45 @@ get_range_info (const_tree name, widest_
> > 2 * HOST_BITS_PER_WIDE_INT))
> return VR_VARYING;
>
> - *min = ri->min;
> - *max = ri->max;
> + *min = ri->get_min ();
> + *max = ri->get_max ();
> return SSA_NAME_RANGE_TYPE (name);
> }
>
> /* Change non-zero bits bitmask of NAME. */
>
> void
> -set_nonzero_bits (tree name, const widest_int &mask)
> +set_nonzero_bits (tree name, const wide_int_ref &mask)
> {
> gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
> if (SSA_NAME_RANGE_INFO (name) == NULL)
> set_range_info (name, VR_RANGE,
> - wi::to_widest (TYPE_MIN_VALUE (TREE_TYPE (name))),
> - wi::to_widest (TYPE_MAX_VALUE (TREE_TYPE (name))));
> + TYPE_MIN_VALUE (TREE_TYPE (name)),
> + TYPE_MAX_VALUE (TREE_TYPE (name)));
> range_info_def *ri = SSA_NAME_RANGE_INFO (name);
> - ri->nonzero_bits
> - = mask & wi::mask <widest_int> (TYPE_PRECISION (TREE_TYPE (name)),
> - false);
> + ri->set_nonzero_bits (mask);
> }
>
> /* Return a widest_int with potentially non-zero bits in SSA_NAME
> NAME, or -1 if unknown. */
>
> -widest_int
> +wide_int
> get_nonzero_bits (const_tree name)
> {
> + unsigned int precision = TYPE_PRECISION (TREE_TYPE (name));
> if (POINTER_TYPE_P (TREE_TYPE (name)))
> {
> struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name);
> if (pi && pi->align)
> - {
> - widest_int al = pi->align - 1;
> - return ((wi::mask <widest_int> (TYPE_PRECISION (TREE_TYPE (name)),
> - false) & ~al)
> - | pi->misalign);
> - }
> - return -1;
> + return wi::shwi (-(int) pi->align | pi->misalign, precision);
> + return wi::shwi (-1, precision);
> }
>
> range_info_def *ri = SSA_NAME_RANGE_INFO (name);
> - if (!ri || (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (name)))
> - > 2 * HOST_BITS_PER_WIDE_INT))
> - return -1;
> + if (!ri)
> + return wi::shwi (-1, precision);
>
> - return ri->nonzero_bits;
> + return ri->get_nonzero_bits ();
> }
>
> /* We no longer need the SSA_NAME expression VAR, release it so that
> @@ -497,8 +487,11 @@ duplicate_ssa_name_range_info (tree name
> if (!range_info)
> return;
>
> - new_range_info = ggc_alloc_range_info_def ();
> - *new_range_info = *range_info;
> + unsigned int precision = TYPE_PRECISION (TREE_TYPE (name));
> + size_t size = (sizeof (range_info_def)
> + + trailing_wide_ints <3>::extra_size (precision));
> + new_range_info = ggc_alloc_range_info_def (size);
> + memcpy (new_range_info, range_info, size);
>
> gcc_assert (range_type == VR_RANGE || range_type == VR_ANTI_RANGE);
> SSA_NAME_ANTI_RANGE_P (name) = (range_type == VR_ANTI_RANGE);
> Index: gcc/tree-ssanames.h
> ===================================================================
> --- gcc/tree-ssanames.h 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/tree-ssanames.h 2013-11-28 11:37:35.998909487 +0000
> @@ -47,13 +47,12 @@ struct GTY(()) ptr_info_def
>
> /* Value range information for SSA_NAMEs representing non-pointer variables.
> */
>
> -struct GTY (()) range_info_def {
> - /* Minimum for value range. */
> - widest_int min;
> - /* Maximum for value range. */
> - widest_int max;
> - /* Non-zero bits - bits not set are guaranteed to be always zero. */
> - widest_int nonzero_bits;
> +struct GTY ((variable_size)) range_info_def {
> + /* Minimum, maximum and nonzero bits. */
> + TRAILING_WIDE_INT_ACCESSOR (min, ints, 0)
> + TRAILING_WIDE_INT_ACCESSOR (max, ints, 1)
> + TRAILING_WIDE_INT_ACCESSOR (nonzero_bits, ints, 2)
> + trailing_wide_ints <3> ints;
> };
>
>
> @@ -70,13 +69,13 @@ #define ssa_name(i) ((*cfun->gimple_df->
> enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
>
> /* Sets the value range to SSA. */
> -extern void set_range_info (tree, enum value_range_type, const widest_int &,
> - const widest_int &);
> +extern void set_range_info (tree, enum value_range_type, const wide_int_ref
> &,
> + const wide_int_ref &);
> /* Gets the value range from SSA. */
> -extern enum value_range_type get_range_info (const_tree, widest_int *,
> - widest_int *);
> -extern void set_nonzero_bits (tree, const widest_int &);
> -extern widest_int get_nonzero_bits (const_tree);
> +extern enum value_range_type get_range_info (const_tree, wide_int *,
> + wide_int *);
> +extern void set_nonzero_bits (tree, const wide_int_ref &);
> +extern wide_int get_nonzero_bits (const_tree);
> extern void init_ssanames (struct function *, int);
> extern void fini_ssanames (void);
> extern void ssanames_print_statistics (void);
> Index: gcc/tree-vect-patterns.c
> ===================================================================
> --- gcc/tree-vect-patterns.c 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/tree-vect-patterns.c 2013-11-27 18:45:46.711684572 +0000
> @@ -2261,13 +2261,13 @@ vect_recog_divmod_pattern (vec<gimple> *
> else
> t3 = t2;
>
> - widest_int oprnd0_min, oprnd0_max;
> + wide_int oprnd0_min, oprnd0_max;
> int msb = 1;
> if (get_range_info (oprnd0, &oprnd0_min, &oprnd0_max) == VR_RANGE)
> {
> - if (!wi::neg_p (oprnd0_min))
> + if (!wi::neg_p (oprnd0_min, TYPE_SIGN (itype)))
> msb = 0;
> - else if (wi::neg_p (oprnd0_max))
> + else if (wi::neg_p (oprnd0_max, TYPE_SIGN (itype)))
> msb = -1;
> }
>
> Index: gcc/tree-vrp.c
> ===================================================================
> --- gcc/tree-vrp.c 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/tree-vrp.c 2013-11-28 11:32:48.572622303 +0000
> @@ -6422,8 +6422,7 @@ maybe_set_nonzero_bits (basic_block bb,
> return;
> }
> cst = gimple_assign_rhs2 (stmt);
> - set_nonzero_bits (var, (get_nonzero_bits (var)
> - & ~wi::to_widest (cst)));
> + set_nonzero_bits (var, wi::bit_and_not (get_nonzero_bits (var), cst));
> }
>
> /* Convert range assertion expressions into the implied copies and
> @@ -6508,8 +6507,8 @@ remove_range_assertions (void)
> single_pred (bb)))
> {
> set_range_info (var, SSA_NAME_RANGE_TYPE (lhs),
> - SSA_NAME_RANGE_INFO (lhs)->min,
> - SSA_NAME_RANGE_INFO (lhs)->max);
> + SSA_NAME_RANGE_INFO (lhs)->get_min (),
> + SSA_NAME_RANGE_INFO (lhs)->get_max ());
> maybe_set_nonzero_bits (bb, var);
> }
> }
> @@ -9534,9 +9533,8 @@ vrp_finalize (void)
> && (TREE_CODE (vr_value[i]->max) == INTEGER_CST)
> && (vr_value[i]->type == VR_RANGE
> || vr_value[i]->type == VR_ANTI_RANGE))
> - set_range_info (name, vr_value[i]->type,
> - wi::to_widest (vr_value[i]->min),
> - wi::to_widest (vr_value[i]->max));
> + set_range_info (name, vr_value[i]->type, vr_value[i]->min,
> + vr_value[i]->max);
> }
>
> /* Free allocated memory. */
> Index: gcc/wide-int.h
> ===================================================================
> --- gcc/wide-int.h 2013-11-27 18:45:17.448816304 +0000
> +++ gcc/wide-int.h 2013-11-28 11:44:39.041731636 +0000
> @@ -653,6 +653,9 @@ class GTY(()) generic_wide_int : public
> HOST_WIDE_INT slow () const;
> HOST_WIDE_INT shigh () const;
>
> + template <typename T>
> + generic_wide_int &operator = (const T &);
> +
> #define BINARY_PREDICATE(OP, F) \
> template <typename T> \
> bool OP (const T &c) const { return wi::F (*this, c); }
> @@ -831,6 +834,15 @@ generic_wide_int <storage>::elt (unsigne
> return this->get_val ()[i];
> }
>
> +template <typename storage>
> +template <typename T>
> +generic_wide_int <storage> &
> +generic_wide_int <storage>::operator = (const T &x)
> +{
> + storage::operator = (x);
> + return *this;
> +}
> +
> namespace wi
> {
> template <>
> @@ -1188,6 +1200,159 @@ get_binary_result (const T1 &, const T2
> return FIXED_WIDE_INT (N) ();
> }
>
> +/* A reference to one element of a trailing_wide_ints structure. */
> +class trailing_wide_int_storage
> +{
> +private:
> + /* The precision of the integer, which is a fixed property of the
> + parent trailing_wide_ints. */
> + unsigned int m_precision;
> +
> + /* A pointer to the length field. */
> + unsigned char *m_len;
> +
> + /* A pointer to the HWI array. There are enough elements to hold all
> + values of precision M_PRECISION. */
> + HOST_WIDE_INT *m_val;
> +
> +public:
> + trailing_wide_int_storage (unsigned int, unsigned char *, HOST_WIDE_INT *);
> +
> + /* The standard generic_wide_int storage methods. */
> + unsigned int get_len () const;
> + unsigned int get_precision () const;
> + const HOST_WIDE_INT *get_val () const;
> + HOST_WIDE_INT *write_val ();
> + void set_len (unsigned int, bool = false);
> +
> + template <typename T>
> + trailing_wide_int_storage &operator = (const T &);
> +};
> +
> +typedef generic_wide_int <trailing_wide_int_storage> trailing_wide_int;
> +
> +/* trailing_wide_int behaves like a wide_int. */
> +namespace wi
> +{
> + template <>
> + struct int_traits <trailing_wide_int_storage>
> + : public int_traits <wide_int_storage> {};
> +}
> +
> +/* An array of N wide_int-like objects that can be put at the end of
> + a variable-sized structure. Use extra_size to calculate how many
> + bytes beyond the sizeof need to be allocated. Use set_precision
> + to initialize the structure. */
> +template <int N>
> +class GTY(()) trailing_wide_ints
> +{
> +private:
> + /* The shared precision of each number. */
> + unsigned short m_precision;
> +
> + /* The shared maximum length of each number. */
> + unsigned char m_max_len;
> +
> + /* The current length of each number. */
> + unsigned char m_len[N];
> +
> + /* The variable-length part of the structure, which always contains
> + at least one HWI. Element I starts at index I * M_MAX_LEN. */
> + HOST_WIDE_INT m_val[1];
> +
> +public:
> + void set_precision (unsigned int);
> + trailing_wide_int operator [] (unsigned int);
> + static size_t extra_size (unsigned int);
> +};
> +
> +inline trailing_wide_int_storage::
> +trailing_wide_int_storage (unsigned int precision, unsigned char *len,
> + HOST_WIDE_INT *val)
> + : m_precision (precision), m_len (len), m_val (val)
> +{
> +}
> +
> +inline unsigned int
> +trailing_wide_int_storage::get_len () const
> +{
> + return *m_len;
> +}
> +
> +inline unsigned int
> +trailing_wide_int_storage::get_precision () const
> +{
> + return m_precision;
> +}
> +
> +inline const HOST_WIDE_INT *
> +trailing_wide_int_storage::get_val () const
> +{
> + return m_val;
> +}
> +
> +inline HOST_WIDE_INT *
> +trailing_wide_int_storage::write_val ()
> +{
> + return m_val;
> +}
> +
> +inline void
> +trailing_wide_int_storage::set_len (unsigned int len, bool is_sign_extended)
> +{
> + *m_len = len;
> + if (!is_sign_extended && len * HOST_BITS_PER_WIDE_INT > m_precision)
> + m_val[len - 1] = sext_hwi (m_val[len - 1],
> + m_precision % HOST_BITS_PER_WIDE_INT);
> +}
> +
> +template <typename T>
> +inline trailing_wide_int_storage &
> +trailing_wide_int_storage::operator = (const T &x)
> +{
> + WIDE_INT_REF_FOR (T) xi (x, m_precision);
> + wi::copy (*this, xi);
> + return *this;
> +}
> +
> +/* Initialize the structure and record that all elements have precision
> + PRECISION. */
> +template <int N>
> +inline void
> +trailing_wide_ints <N>::set_precision (unsigned int precision)
> +{
> + m_precision = precision;
> + m_max_len = ((precision + HOST_BITS_PER_WIDE_INT - 1)
> + / HOST_BITS_PER_WIDE_INT);
> +}
> +
> +/* Return a reference to element INDEX. */
> +template <int N>
> +inline trailing_wide_int
> +trailing_wide_ints <N>::operator [] (unsigned int index)
> +{
> + return trailing_wide_int_storage (m_precision, &m_len[index],
> + &m_val[index * m_max_len]);
> +}
> +
> +/* Return how many extra bytes need to be added to the end of the structure
> + in order to handle N wide_ints of precision PRECISION. */
> +template <int N>
> +inline size_t
> +trailing_wide_ints <N>::extra_size (unsigned int precision)
> +{
> + unsigned int max_len = ((precision + HOST_BITS_PER_WIDE_INT - 1)
> + / HOST_BITS_PER_WIDE_INT);
> + return (N * max_len - 1) * sizeof (HOST_WIDE_INT);
> +}
> +
> +/* This macro is used in structures that end with a trailing_wide_ints field
> + called FIELD. It declares get_NAME() and set_NAME() methods to access
> + element I of FIELD. */
> +#define TRAILING_WIDE_INT_ACCESSOR(NAME, FIELD, I) \
> + trailing_wide_int get_##NAME () { return FIELD[I]; } \
> + template <typename T> void set_##NAME (const T &x) { FIELD[I] = x; }
> +
> namespace wi
> {
> /* Implementation of int_traits for primitive integer types like "int". */
> @@ -2726,6 +2891,24 @@ gt_pch_nx (generic_wide_int <T> *, void
> {
> }
>
> +template<int N>
> +void
> +gt_ggc_mx (trailing_wide_ints <N> *)
> +{
> +}
> +
> +template<int N>
> +void
> +gt_pch_nx (trailing_wide_ints <N> *)
> +{
> +}
> +
> +template<int N>
> +void
> +gt_pch_nx (trailing_wide_ints <N> *, void (*) (void *, void *), void *)
> +{
> +}
> +
> namespace wi
> {
> /* Used for overloaded functions in which the only other acceptable