Speaking in terms of a patch: Index: tree.h =================================================================== --- tree.h (revision 203690) +++ tree.h (working copy) @@ -5184,14 +5184,11 @@ wi::int_traits <const_tree>::decompose ( / HOST_BITS_PER_WIDE_INT); unsigned int xprecision = get_precision (x); - gcc_assert (precision >= xprecision); + gcc_checking_assert (precision >= xprecision && precision != 0); - /* Got to be careful of precision 0 values. */ - if (precision) - len = MIN (len, max_len); if (TYPE_SIGN (TREE_TYPE (x)) == UNSIGNED) { - unsigned int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1); + unsigned int small_prec = xprecision & (HOST_BITS_PER_WIDE_INT - 1); if (small_prec) { /* We have to futz with this because the canonization for @@ -5201,7 +5198,7 @@ wi::int_traits <const_tree>::decompose ( { for (unsigned int i = 0; i < len - 1; i++) scratch[i] = val[i]; - scratch[len - 1] = sext_hwi (val[len - 1], precision); + scratch[len - 1] = sext_hwi (val[len - 1], small_prec); return wi::storage_ref (scratch, len, precision); } }
the precision 0 thing is gone as far as I understand? Also sign-extending the upper hwi must be done with precision % HOST_BITS_PER_WIDE_INT, no? And it assumes that we only ever have to extend the upper most HWI, thus 'len' is never too big. I note that we immediately return in the above case, so if (precision < xprecision + HOST_BITS_PER_WIDE_INT) { len = wi::force_to_size (scratch, val, len, xprecision, precision, UNSIGNED); return wi::storage_ref (scratch, len, precision); } applies only when the desired precision is a multiple of a HWI. I assume it adds that extra zero word in case the MSB is set, right? I am confused about the condition written here and how we look at precision and not xprecision when deciding how to extend - given a 8-bit precision unsigned 0xff and precision == 64 we do not even consider sign-extending the value because we look at precision and not xprecision. Don't we need to look at xprecision here? After all an assert precision == xprecision does not work in this routine. Quickly execute.exp tested only. To avoid code quality wreckage we have to implement a different way of allocating the 'scratch' storage of wide_int_ref_storage (well, ideally we wouldn't need it ...). I thought of simply allocating it via alloca (), but we need to do that in all callers that build a wide_int_ref (eventually via a hidden default arg). But as that's a template specialization of generic_wide_int ... so the option is to provide a function wrapper inside wi:: for this, like template <typename T> wide_int_ref wi::ref (const T &t, HOST_WIDE_INT *scratch = XALLOCAVEC (HOST_WIDE_INT, WIDE_INT_MAX_ELTS)) { return wide_int_ref (t, scratch); } and amend the storage constructors to get a scratch argument. The reason for all this is that otherwise the wide_int_ref object escapes when we pass the scratch storage to the workers in int_traits <const_tree>. Thanks, Richard.