Jakub Jelinek <[email protected]> writes:
> On Mon, Oct 09, 2023 at 03:44:10PM +0200, Jakub Jelinek wrote:
>> Thanks, just quick answers, will work on patch adjustments after trying to
>> get rid of rwide_int (seems dwarf2out has very limited needs from it, just
>> some routine to construct it in GCed memory (and never change afterwards)
>> from const wide_int_ref & or so, and then working operator ==,
>> get_precision, elt, get_len and get_val methods, so I think we could just
>> have a struct dw_wide_int { unsigned int prec, len; HOST_WIDE_INT val[1]; };
>> and perform the methods on it after converting to a storage ref.
>
> Now in patch form (again, incremental).
>
>> > Does the variable-length memcpy pay for itself? If so, perhaps that's a
>> > sign that we should have a smaller inline buffer for this class (say 2
>> > HWIs).
>>
>> Guess I'll try to see what results in smaller .text size.
>
> I've left the memcpy changes into a separate patch (incremental, attached).
> Seems that second patch results in .text growth by 16256 bytes (0.04%),
> though I'd bet it probably makes compile time tiny bit faster because it
> replaces an out of line memcpy (caused by variable length) with inlined one.
>
> With even the third one it shrinks by 84544 bytes (0.21% down), but the
> extra statistics patch then shows massive number of allocations after
> running make check-gcc check-g++ check-gfortran for just a minute or two.
> On the widest_int side, I see (first number from sort | uniq -c | sort -nr,
> second the estimated or final len)
> 7289034 4
> 173586 5
> 21819 6
> i.e. there are tons of widest_ints which need len 4 (or perhaps just
> have it as upper estimation), maybe even 5 would be nice.
Thanks for running the stats. That's definitely a lot more than I expected.
> On the wide_int side, I see
> 155291 576
> (supposedly because of bound_wide_int, where we create wide_int_ref from
> the 576-bit precision bound_wide_int and then create 576-bit wide_int when
> using unary or binary operation on that).
576 bits seems quite a lot for a loop bound. We're enterning near-infinite
territory with 128 bits. :) But I don't want to rehash old discussions.
If we take this size for wide_int as given, then...
> So, perhaps we could get away with say WIDEST_INT_MAX_INL_ELTS of 5 or 6
> instead of 9 but keep WIDE_INT_MAX_INL_ELTS at 9 (or whatever is computed
> from MAX_BITSIZE_MODE_ANY_INT?). Or keep it at 9 for both (i.e. without
> the third patch).
...I agree we might as well keep the widest_int size the same for
simplicity. It'd only be worth distinguishing them if we have positive
proof that it's worthwhile.
So going with patches 1 + 2 sounds good to me, but I don't have a strong
preference.
On the wide-int.cc changes:
> @@ -1469,6 +1452,36 @@ wi::mul_internal (HOST_WIDE_INT *val, co
> return 1;
> }
>
> + /* The sizes here are scaled to support a 2x WIDE_INT_MAX_INL_PRECISION by
> 2x
> + WIDE_INT_MAX_INL_PRECISION yielding a 4x WIDE_INT_MAX_INL_PRECISION
> + result. */
> +
> + unsigned HOST_HALF_WIDE_INT
> + ubuf[4 * WIDE_INT_MAX_INL_PRECISION / HOST_BITS_PER_HALF_WIDE_INT];
> + unsigned HOST_HALF_WIDE_INT
> + vbuf[4 * WIDE_INT_MAX_INL_PRECISION / HOST_BITS_PER_HALF_WIDE_INT];
> + /* The '2' in 'R' is because we are internally doing a full
> + multiply. */
> + unsigned HOST_HALF_WIDE_INT
> + rbuf[2 * 4 * WIDE_INT_MAX_INL_PRECISION / HOST_BITS_PER_HALF_WIDE_INT];
> + const HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 <<
> HOST_BITS_PER_HALF_WIDE_INT) - 1;
> + unsigned HOST_HALF_WIDE_INT *u = ubuf;
> + unsigned HOST_HALF_WIDE_INT *v = vbuf;
> + unsigned HOST_HALF_WIDE_INT *r = rbuf;
> +
> + if (prec > WIDE_INT_MAX_INL_PRECISION && !high)
> + prec = (op1len + op2len + 1) * HOST_BITS_PER_WIDE_INT;
Changing the precision looked a bit dangerous at first, but I agree it
looks correct in context, in that nothing later on seems to require prec
to be the real precision of the number. But I wonder whether we should
instead do:
if (!high)
prec = MIN ((op1len + op2len + 1) * HOST_BITS_PER_WIDE_INT, prec);
so that the assumption gets a bit more testing. Same idea for the others.
I.e. in any case where we think it's safe to reduce a precision or
length for out-of-line buffers, I think we should try to do the same
for inline ones.
I'm not sure off-hand why + 1 is safe here but + 2 is needed for the
write_val estimate. Might be worth a comment in one place or the other.
> + unsigned int blocks_needed = BLOCKS_NEEDED (prec);
> + unsigned int half_blocks_needed = blocks_needed * 2;
> + if (UNLIKELY (prec > WIDE_INT_MAX_INL_PRECISION))
> + {
> + unsigned HOST_HALF_WIDE_INT *buf
> + = XALLOCAVEC (unsigned HOST_HALF_WIDE_INT, 4 * 4 * blocks_needed);
> + u = buf;
> + v = u + 4 * blocks_needed;
> + r = v + 4 * blocks_needed;
> + }
> +
> /* We do unsigned mul and then correct it. */
> wi_unpack (u, op1val, op1len, half_blocks_needed, prec, SIGNED);
> wi_unpack (v, op2val, op2len, half_blocks_needed, prec, SIGNED);
> [...]
> @@ -2399,9 +2453,12 @@ from_int (int i)
> static void
> assert_deceq (const char *expected, const wide_int_ref &wi, signop sgn)
> {
> - char buf[WIDE_INT_PRINT_BUFFER_SIZE];
> - print_dec (wi, buf, sgn);
> - ASSERT_STREQ (expected, buf);
> + char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p = buf;
> + unsigned len = wi.get_len ();
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS))
> + p = XALLOCAVEC (char, len * HOST_BITS_PER_WIDE_INT / 4 + 4);
Is this size enough for decimal? E.g. to go back to the 576-bit example,
2^575 is O(10^173), but 576/4+4 == 148.
> + print_dec (wi, p, sgn);
> + ASSERT_STREQ (expected, p);
> }
>
> /* Likewise for base 16. */
The wide-int.cc changes LGTM otherwise. I don't think I'm the right
person to review the other changes.
Thanks,
Richard
>
> --- gcc/poly-int.h.jj 2023-10-09 14:37:45.883940062 +0200
> +++ gcc/poly-int.h 2023-10-09 17:05:26.629828329 +0200
> @@ -96,7 +96,7 @@ struct poly_coeff_traits<T, wi::VAR_PREC
> };
>
> template<typename T>
> -struct poly_coeff_traits<T, wi::CONST_PRECISION>
> +struct poly_coeff_traits<T, wi::INL_CONST_PRECISION>
> {
> typedef WI_UNARY_RESULT (T) result;
> typedef int int_type;
> @@ -110,14 +110,13 @@ struct poly_coeff_traits<T, wi::CONST_PR
> };
>
> template<typename T>
> -struct poly_coeff_traits<T, wi::WIDEST_CONST_PRECISION>
> +struct poly_coeff_traits<T, wi::CONST_PRECISION>
> {
> typedef WI_UNARY_RESULT (T) result;
> typedef int int_type;
> /* These types are always signed. */
> static const int signedness = 1;
> static const int precision = wi::int_traits<T>::precision;
> - static const int inl_precision = wi::int_traits<T>::inl_precision;
> static const int rank = precision * 2 / CHAR_BIT;
>
> template<typename Arg>
> --- gcc/double-int.h.jj 2023-01-02 09:32:22.747280053 +0100
> +++ gcc/double-int.h 2023-10-09 17:06:03.446317336 +0200
> @@ -440,7 +440,7 @@ namespace wi
> template <>
> struct int_traits <double_int>
> {
> - static const enum precision_type precision_type = CONST_PRECISION;
> + static const enum precision_type precision_type = INL_CONST_PRECISION;
> static const bool host_dependent_precision = true;
> static const unsigned int precision = HOST_BITS_PER_DOUBLE_INT;
> static unsigned int get_precision (const double_int &);
> --- gcc/wide-int.h.jj 2023-10-09 16:06:39.326805176 +0200
> +++ gcc/wide-int.h 2023-10-09 17:29:20.016951691 +0200
> @@ -343,8 +343,8 @@ template <int N> class widest_int_storag
>
> typedef generic_wide_int <wide_int_storage> wide_int;
> typedef FIXED_WIDE_INT (ADDR_MAX_PRECISION) offset_int;
> -typedef generic_wide_int <widest_int_storage <WIDE_INT_MAX_INL_PRECISION> >
> widest_int;
> -typedef generic_wide_int <widest_int_storage <WIDE_INT_MAX_INL_PRECISION *
> 2> > widest2_int;
> +typedef generic_wide_int <widest_int_storage <WIDEST_INT_MAX_PRECISION> >
> widest_int;
> +typedef generic_wide_int <widest_int_storage <WIDEST_INT_MAX_PRECISION * 2>
> > widest2_int;
>
> /* wi::storage_ref can be a reference to a primitive type,
> so this is the conservatively-correct setting. */
> @@ -394,13 +394,13 @@ namespace wi
> /* The integer has a variable precision but no defined signedness. */
> VAR_PRECISION,
>
> - /* The integer has a constant precision (known at GCC compile time)
> - and is signed. */
> - CONST_PRECISION,
> -
> - /* Like CONST_PRECISION, but with WIDEST_INT_MAX_PRECISION or larger
> - precision where not all elements of arrays are always present. */
> - WIDEST_CONST_PRECISION
> + /* The integer has a constant precision (known at GCC compile time),
> + is signed and all elements are in inline buffer. */
> + INL_CONST_PRECISION,
> +
> + /* Like INL_CONST_PRECISION, but elements can be heap allocated for
> + larger lengths. */
> + CONST_PRECISION
> };
>
> /* This class, which has no default implementation, is expected to
> @@ -410,15 +410,10 @@ namespace wi
> Classifies the type of T.
>
> static const unsigned int precision;
> - Only defined if precision_type == CONST_PRECISION or
> - precision_type == WIDEST_CONST_PRECISION. Specifies the
> + Only defined if precision_type == INL_CONST_PRECISION or
> + precision_type == CONST_PRECISION. Specifies the
> precision of all integers of type T.
>
> - static const unsigned int inl_precision;
> - Only defined if precision_type == WIDEST_CONST_PRECISION.
> - Specifies precision which is represented in the inline
> - arrays.
> -
> static const bool host_dependent_precision;
> True if the precision of T depends (or can depend) on the host.
>
> @@ -441,10 +436,10 @@ namespace wi
> struct binary_traits;
>
> /* Specify the result type for each supported combination of binary
> - inputs. Note that CONST_PRECISION, WIDEST_CONST_PRECISION and
> + inputs. Note that INL_CONST_PRECISION, CONST_PRECISION and
> VAR_PRECISION cannot be mixed, in order to give stronger type
> - checking. When both inputs are CONST_PRECISION or both are
> - WIDEST_CONST_PRECISION, they must have the same precision. */
> + checking. When both inputs are INL_CONST_PRECISION or both are
> + CONST_PRECISION, they must have the same precision. */
> template <typename T1, typename T2>
> struct binary_traits <T1, T2, FLEXIBLE_PRECISION, FLEXIBLE_PRECISION>
> {
> @@ -461,7 +456,7 @@ namespace wi
> };
>
> template <typename T1, typename T2>
> - struct binary_traits <T1, T2, FLEXIBLE_PRECISION, CONST_PRECISION>
> + struct binary_traits <T1, T2, FLEXIBLE_PRECISION, INL_CONST_PRECISION>
> {
> /* Spelled out explicitly (rather than through FIXED_WIDE_INT)
> so as not to confuse gengtype. */
> @@ -474,10 +469,10 @@ namespace wi
> };
>
> template <typename T1, typename T2>
> - struct binary_traits <T1, T2, FLEXIBLE_PRECISION, WIDEST_CONST_PRECISION>
> + struct binary_traits <T1, T2, FLEXIBLE_PRECISION, CONST_PRECISION>
> {
> typedef generic_wide_int < widest_int_storage
> - <int_traits <T2>::inl_precision> > result_type;
> + <int_traits <T2>::precision> > result_type;
> typedef result_type operator_result;
> typedef bool predicate_result;
> typedef result_type signed_shift_result_type;
> @@ -493,7 +488,7 @@ namespace wi
> };
>
> template <typename T1, typename T2>
> - struct binary_traits <T1, T2, CONST_PRECISION, FLEXIBLE_PRECISION>
> + struct binary_traits <T1, T2, INL_CONST_PRECISION, FLEXIBLE_PRECISION>
> {
> /* Spelled out explicitly (rather than through FIXED_WIDE_INT)
> so as not to confuse gengtype. */
> @@ -506,10 +501,10 @@ namespace wi
> };
>
> template <typename T1, typename T2>
> - struct binary_traits <T1, T2, WIDEST_CONST_PRECISION, FLEXIBLE_PRECISION>
> + struct binary_traits <T1, T2, CONST_PRECISION, FLEXIBLE_PRECISION>
> {
> typedef generic_wide_int < widest_int_storage
> - <int_traits <T1>::inl_precision> > result_type;
> + <int_traits <T1>::precision> > result_type;
> typedef result_type operator_result;
> typedef bool predicate_result;
> typedef result_type signed_shift_result_type;
> @@ -517,7 +512,7 @@ namespace wi
> };
>
> template <typename T1, typename T2>
> - struct binary_traits <T1, T2, CONST_PRECISION, CONST_PRECISION>
> + struct binary_traits <T1, T2, INL_CONST_PRECISION, INL_CONST_PRECISION>
> {
> STATIC_ASSERT (int_traits <T1>::precision == int_traits <T2>::precision);
> /* Spelled out explicitly (rather than through FIXED_WIDE_INT)
> @@ -531,11 +526,11 @@ namespace wi
> };
>
> template <typename T1, typename T2>
> - struct binary_traits <T1, T2, WIDEST_CONST_PRECISION,
> WIDEST_CONST_PRECISION>
> + struct binary_traits <T1, T2, CONST_PRECISION, CONST_PRECISION>
> {
> STATIC_ASSERT (int_traits <T1>::precision == int_traits <T2>::precision);
> typedef generic_wide_int < widest_int_storage
> - <int_traits <T1>::inl_precision> > result_type;
> + <int_traits <T1>::precision> > result_type;
> typedef result_type operator_result;
> typedef bool predicate_result;
> typedef result_type signed_shift_result_type;
> @@ -1191,8 +1186,7 @@ inline wide_int_storage::wide_int_storag
> {
> STATIC_ASSERT (!wi::int_traits<T>::host_dependent_precision);
> STATIC_ASSERT (wi::int_traits<T>::precision_type != wi::CONST_PRECISION);
> - STATIC_ASSERT (wi::int_traits<T>::precision_type
> - != wi::WIDEST_CONST_PRECISION);
> + STATIC_ASSERT (wi::int_traits<T>::precision_type !=
> wi::INL_CONST_PRECISION);
> WIDE_INT_REF_FOR (T) xi (x);
> precision = xi.precision;
> if (UNLIKELY (precision > WIDE_INT_MAX_INL_PRECISION))
> @@ -1246,8 +1240,7 @@ wide_int_storage::operator = (const T &x
> {
> STATIC_ASSERT (!wi::int_traits<T>::host_dependent_precision);
> STATIC_ASSERT (wi::int_traits<T>::precision_type != wi::CONST_PRECISION);
> - STATIC_ASSERT (wi::int_traits<T>::precision_type
> - != wi::WIDEST_CONST_PRECISION);
> + STATIC_ASSERT (wi::int_traits<T>::precision_type !=
> wi::INL_CONST_PRECISION);
> WIDE_INT_REF_FOR (T) xi (x);
> if (UNLIKELY (precision != xi.precision))
> {
> @@ -1391,7 +1384,7 @@ namespace wi
> template <int N>
> struct int_traits < fixed_wide_int_storage <N> >
> {
> - static const enum precision_type precision_type = CONST_PRECISION;
> + static const enum precision_type precision_type = INL_CONST_PRECISION;
> static const bool host_dependent_precision = false;
> static const bool is_sign_extended = true;
> static const bool needs_write_val_arg = false;
> @@ -1504,7 +1497,7 @@ class GTY(()) widest_int_storage
> private:
> union
> {
> - HOST_WIDE_INT val[WIDE_INT_MAX_HWIS (N)];
> + HOST_WIDE_INT val[WIDE_INT_MAX_INL_ELTS];
> HOST_WIDE_INT *valp;
> } GTY((skip)) u;
> unsigned int len;
> @@ -1536,13 +1529,11 @@ namespace wi
> template <int N>
> struct int_traits < widest_int_storage <N> >
> {
> - static const enum precision_type precision_type = WIDEST_CONST_PRECISION;
> + static const enum precision_type precision_type = CONST_PRECISION;
> static const bool host_dependent_precision = false;
> static const bool is_sign_extended = true;
> static const bool needs_write_val_arg = true;
> - static const unsigned int precision
> - = N / WIDE_INT_MAX_INL_PRECISION * WIDEST_INT_MAX_PRECISION;
> - static const unsigned int inl_precision = N;
> + static const unsigned int precision = N;
> template <typename T1, typename T2>
> static WIDEST_INT (N) get_binary_result (const T1 &, const T2 &);
> template <typename T1, typename T2>
> @@ -1561,8 +1552,7 @@ inline widest_int_storage <N>::widest_in
> /* Check for type compatibility. We don't want to initialize a
> widest integer from something like a wide_int. */
> WI_BINARY_RESULT (T, WIDEST_INT (N)) *assertion ATTRIBUTE_UNUSED;
> - wi::copy (*this, WIDE_INT_REF_FOR (T) (x, N / WIDE_INT_MAX_INL_PRECISION
> - * WIDEST_INT_MAX_PRECISION));
> + wi::copy (*this, WIDE_INT_REF_FOR (T) (x, N));
> }
>
> template <int N>
> @@ -1570,7 +1560,7 @@ inline
> widest_int_storage <N>::widest_int_storage (const widest_int_storage &x)
> {
> len = x.len;
> - if (UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT))
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS))
> {
> u.valp = XNEWVEC (HOST_WIDE_INT, len);
> memcpy (u.valp, x.u.valp, len * sizeof (HOST_WIDE_INT));
> @@ -1582,7 +1572,7 @@ widest_int_storage <N>::widest_int_stora
> template <int N>
> inline widest_int_storage <N>::~widest_int_storage ()
> {
> - if (UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT))
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS))
> XDELETEVEC (u.valp);
> }
>
> @@ -1590,14 +1580,14 @@ template <int N>
> inline widest_int_storage <N>&
> widest_int_storage <N>::operator = (const widest_int_storage <N> &x)
> {
> - if (UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT))
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS))
> {
> if (this == &x)
> return *this;
> XDELETEVEC (u.valp);
> }
> len = x.len;
> - if (UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT))
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS))
> {
> u.valp = XNEWVEC (HOST_WIDE_INT, len);
> memcpy (u.valp, x.u.valp, len * sizeof (HOST_WIDE_INT));
> @@ -1615,11 +1605,10 @@ widest_int_storage <N>::operator = (cons
> /* Check for type compatibility. We don't want to assign a
> widest integer from something like a wide_int. */
> WI_BINARY_RESULT (T, WIDEST_INT (N)) *assertion ATTRIBUTE_UNUSED;
> - if (UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT))
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS))
> XDELETEVEC (u.valp);
> len = 0;
> - wi::copy (*this, WIDE_INT_REF_FOR (T) (x, N / WIDE_INT_MAX_INL_PRECISION
> - * WIDEST_INT_MAX_PRECISION));
> + wi::copy (*this, WIDE_INT_REF_FOR (T) (x, N));
> return *this;
> }
>
> @@ -1627,14 +1616,14 @@ template <int N>
> inline unsigned int
> widest_int_storage <N>::get_precision () const
> {
> - return N / WIDE_INT_MAX_INL_PRECISION * WIDEST_INT_MAX_PRECISION;
> + return N;
> }
>
> template <int N>
> inline const HOST_WIDE_INT *
> widest_int_storage <N>::get_val () const
> {
> - return UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT) ? u.valp : u.val;
> + return UNLIKELY (len > WIDE_INT_MAX_INL_ELTS) ? u.valp : u.val;
> }
>
> template <int N>
> @@ -1648,10 +1637,10 @@ template <int N>
> inline HOST_WIDE_INT *
> widest_int_storage <N>::write_val (unsigned int l)
> {
> - if (UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT))
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS))
> XDELETEVEC (u.valp);
> len = l;
> - if (UNLIKELY (l > N / HOST_BITS_PER_WIDE_INT))
> + if (UNLIKELY (l > WIDE_INT_MAX_INL_ELTS))
> {
> u.valp = XNEWVEC (HOST_WIDE_INT, l);
> return u.valp;
> @@ -1664,8 +1653,8 @@ inline void
> widest_int_storage <N>::set_len (unsigned int l, bool)
> {
> gcc_checking_assert (l <= len);
> - if (UNLIKELY (len > N / HOST_BITS_PER_WIDE_INT)
> - && l <= N / HOST_BITS_PER_WIDE_INT)
> + if (UNLIKELY (len > WIDE_INT_MAX_INL_ELTS)
> + && l <= WIDE_INT_MAX_INL_ELTS)
> {
> HOST_WIDE_INT *valp = u.valp;
> memcpy (u.val, valp, l * sizeof (u.val[0]));
> @@ -1721,7 +1710,7 @@ inline unsigned int
> wi::int_traits < widest_int_storage <N> >::
> get_binary_precision (const T1 &, const T2 &)
> {
> - return N / WIDE_INT_MAX_INL_PRECISION * WIDEST_INT_MAX_PRECISION;
> + return N;
> }
>
> /* A reference to one element of a trailing_wide_ints structure. */
> @@ -2193,8 +2182,8 @@ template <typename T1, typename T2>
> inline unsigned int
> wi::get_binary_precision (const T1 &x, const T2 &y)
> {
> - return wi::int_traits <WI_BINARY_RESULT (T1, T2)>::get_binary_precision (x,
> - y);
> + using res_traits = wi::int_traits <WI_BINARY_RESULT (T1, T2)>;
> + return res_traits::get_binary_precision (x, y);
> }
>
> /* Copy the contents of Y to X, but keeping X's current precision. */
> @@ -2683,8 +2672,8 @@ wi::bswap (const T &x)
> WI_UNARY_RESULT_VAR (result, val, T, x);
> unsigned int precision = get_precision (result);
> WIDE_INT_REF_FOR (T) xi (x, precision);
> - if (result.needs_write_val_arg)
> - gcc_unreachable (); /* bswap on widest_int makes no sense. */
> + static_assert (!result.needs_write_val_arg,
> + "bswap on widest_int makes no sense");
> result.set_len (bswap_large (val, xi.val, xi.len, precision));
> return result;
> }
> @@ -2697,8 +2686,8 @@ wi::bitreverse (const T &x)
> WI_UNARY_RESULT_VAR (result, val, T, x);
> unsigned int precision = get_precision (result);
> WIDE_INT_REF_FOR (T) xi (x, precision);
> - if (result.needs_write_val_arg)
> - gcc_unreachable (); /* bitreverse on widest_int makes no sense. */
> + static_assert (!result.needs_write_val_arg,
> + "bitreverse on widest_int makes no sense");
> result.set_len (bitreverse_large (val, xi.val, xi.len, precision));
> return result;
> }
> @@ -3127,8 +3116,8 @@ wi::mul_high (const T1 &x, const T2 &y,
> unsigned int precision = get_precision (result);
> WIDE_INT_REF_FOR (T1) xi (x, precision);
> WIDE_INT_REF_FOR (T2) yi (y, precision);
> - if (result.needs_write_val_arg)
> - gcc_unreachable (); /* mul_high on widest_int doesn't make sense. */
> + static_assert (!result.needs_write_val_arg,
> + "mul_high on widest_int doesn't make sense");
> result.set_len (mul_internal (val, xi.val, xi.len,
> yi.val, yi.len, precision,
> sgn, 0, true));
> --- gcc/tree.h.jj 2023-10-09 14:37:45.880940104 +0200
> +++ gcc/tree.h 2023-10-09 17:04:47.138376452 +0200
> @@ -6259,13 +6259,10 @@ namespace wi
> struct int_traits <extended_tree <N> >
> {
> static const enum precision_type precision_type
> - = N == ADDR_MAX_PRECISION ? CONST_PRECISION : WIDEST_CONST_PRECISION;
> + = N == ADDR_MAX_PRECISION ? INL_CONST_PRECISION : CONST_PRECISION;
> static const bool host_dependent_precision = false;
> static const bool is_sign_extended = true;
> static const unsigned int precision = N;
> - static const unsigned int inl_precision
> - = N == ADDR_MAX_PRECISION ? 0
> - : N / WIDEST_INT_MAX_PRECISION * WIDE_INT_MAX_INL_PRECISION;
> };
>
> typedef extended_tree <WIDEST_INT_MAX_PRECISION> widest_extended_tree;
>
> Jakub