On Thu, Nov 28, 2013 at 12:58 PM, Richard Sandiford <rdsandif...@googlemail.com> wrote: > Jakub Jelinek <ja...@redhat.com> 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 <mikest...@comcast.net> 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