summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog.wide-int17
-rw-r--r--gcc/builtins.c7
-rw-r--r--gcc/gimple-pretty-print.c6
-rw-r--r--gcc/tree-ssa-ccp.c37
-rw-r--r--gcc/tree-ssa-loop-niter.c17
-rw-r--r--gcc/tree-ssanames.c69
-rw-r--r--gcc/tree-ssanames.h25
-rw-r--r--gcc/tree-vect-patterns.c6
-rw-r--r--gcc/tree-vrp.c12
-rw-r--r--gcc/wide-int.h183
10 files changed, 279 insertions, 100 deletions
diff --git a/gcc/ChangeLog.wide-int b/gcc/ChangeLog.wide-int
index eedd8a7298e..856fca13881 100644
--- a/gcc/ChangeLog.wide-int
+++ b/gcc/ChangeLog.wide-int
@@ -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.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 13fd0ffe57e..ddca5471810 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -3125,7 +3125,7 @@ determine_block_size (tree len, rtx len_rtx,
}
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_rtx,
/* 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
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index e0786342f69..7458647057a 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -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))
{
- 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 *buffer, tree node, int spc)
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);
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index c836f53defe..bad969648a7 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -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);
}
}
}
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index f912a0d813e..a50b9e37dcf 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -125,7 +125,7 @@ static void
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, tree type, tree var, mpz_t off,
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, tree type, tree var, mpz_t off,
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, tree type, tree var, mpz_t off,
}
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
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 4141cc4a127..4c04a8c8af5 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -182,19 +182,22 @@ make_ssa_name_fn (struct function *fn, tree var, gimple stmt)
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_range_type range_type,
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_range_type range_type,
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_int *min, widest_int *max)
> 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, enum value_range_type range_type,
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);
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index ff4f85adf26..23c988cb2a2 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -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 @@ struct GTY (()) range_info_def {
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);
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index da4cc94f7b7..ebfe10ee321 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -2261,13 +2261,13 @@ vect_recog_divmod_pattern (vec<gimple> *stmts,
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;
}
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index a7475ffcbfa..96e345726f2 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -6422,8 +6422,7 @@ maybe_set_nonzero_bits (basic_block bb, tree var)
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. */
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
index a60389f6620..9be21021259 100644
--- a/gcc/wide-int.h
+++ b/gcc/wide-int.h
@@ -653,6 +653,9 @@ 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 (unsigned int i) const
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 (*) (void *, void *), 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