This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: status of wide-int patch.
- From: Richard Sandiford <rsandifo at linux dot vnet dot ibm dot com>
- To: Kyrill Tkachov <kyrylo dot tkachov at arm dot com>
- Cc: Kenneth Zadeck <zadeck at naturalbridge dot com>, gcc <gcc at gcc dot gnu dot org>, Richard Biener <rguenther at suse dot de>, Mike Stump <mikestump at comcast dot net>
- Date: Tue, 29 Apr 2014 16:35:46 +0100
- Subject: Re: status of wide-int patch.
- Authentication-results: sourceware.org; auth=none
- References: <535E89E8 dot 1080604 at naturalbridge dot com> <535F9D87 dot 9090807 at arm dot com>
Kyrill Tkachov <kyrylo.tkachov@arm.com> writes:
> On 28/04/14 18:03, Kenneth Zadeck wrote:
>> At this point we have believe that we have addressed all of the concerns
>> that the community has made about the wide-int branch. We have also
>> had each of the sections of the branch approved by the area maintainers.
>>
>> We are awaiting a clean build on the arm
>
> Unfortunately arm bootstrap fails a bit further down the line in stage2 while
> building libstdc++-v3/src/c++98/ios.cc:
>
> xgcc: internal compiler error: Segmentation fault (program cc1plus)
> Please submit a full bug report,
> with preprocessed source if appropriate.
> See <http://gcc.gnu.org/bugs.html> for instructions.
>
> Running the cc1plus subcommand through gdb gives:
> Program received signal SIGSEGV, Segmentation fault.
> 0x005c32c8 in real_to_decimal_for_mode(char*, real_value const*, unsigned int,
> unsigned int, int, machine_mode) ()
> (gdb) bt
> #0 0x005c32c8 in real_to_decimal_for_mode(char*, real_value const*, unsigned
> int, unsigned int, int, machine_mode) ()
> #1 0x000033f6 in ?? ()
> Backtrace stopped: previous frame identical to this frame (corrupt stack?)
> (gdb)
>
> The debug info seems to be scarce here, any hints on where to look?
I saw the same thing on 32-bit s390-linux-gnu. It was due to a bug
in the HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_LONG part of real_to_integer,
which would read from before the sig[] buffer if the array size is odd.
The conversion to real_int also meant that we were passing the bit count
"w" to the "need_canon_p" parameter of from_array. "w" looks bogus to me;
the integer that we're constructing in val[] has precision
"words * HOST_BITS_PER_WIDE_INT", with the top bit being the same
as the significand. It seems simpler to do the operation on that
precision instead. This also avoids the need for a fixed_wide_int,
since "words * HOST_BITS_PER_WIDE_INT" takes the same number of HWIs
as the final wide_int result.
This patch seems to fix the failure for me and means that the stage2
real.s produced on s390-linux-gnu is the same as that produced by
s390x-linux-gnu -m31. I'll test on s390-linux-gnu overnight.
Thanks,
Richard
Index: gcc/real.c
===================================================================
--- gcc/real.c (revision 209874)
+++ gcc/real.c (working copy)
@@ -1377,13 +1377,10 @@
wide_int
real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
{
- typedef FIXED_WIDE_INT (WIDE_INT_MAX_PRECISION * 2) real_int;
- HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+ HOST_WIDE_INT val[2 * WIDE_INT_MAX_ELTS];
int exp;
- int words;
+ int words, w;
wide_int result;
- real_int tmp;
- int w;
switch (r->cl)
{
@@ -1415,11 +1412,13 @@
if (exp > precision)
goto overflow;
+ /* Put the significand into a wide_int that has precision W, which
+ is the smallest HWI-multiple that has at least PRECISION bits.
+ This ensures that the top bit of the significand is in the
+ top bit of the wide_int. */
words = (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
+ w = words * HOST_BITS_PER_WIDE_INT;
- for (unsigned int i = 0; i < ARRAY_SIZE (val); i++)
- val[i] = 0;
-
#if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
for (int i = 0; i < words; i++)
{
@@ -1427,27 +1426,23 @@
val[i] = (j < 0) ? 0 : r->sig[j];
}
#else
- gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG);
+ gcc_assert (HOST_BITS_PER_WIDE_INT == 2 * HOST_BITS_PER_LONG);
for (int i = 0; i < words; i++)
{
- int j = SIGSZ - (words * 2) + (i + 2) + 1;
+ int j = SIGSZ - (words * 2) + (i * 2);
if (j < 0)
val[i] = 0;
else
- {
- val[i] = r->sig[j];
- unsigned HOST_WIDE_INT v = val[i];
- v <<= HOST_BITS_PER_LONG;
- val[i] = v;
- val[i] |= r->sig[j - 1];
- }
+ val[i] = r->sig[j];
+ j += 1;
+ if (j >= 0)
+ val[i] |= (unsigned HOST_WIDE_INT) r->sig[j] << HOST_BITS_PER_LONG;
}
#endif
- w = SIGSZ * HOST_BITS_PER_LONG + words * HOST_BITS_PER_WIDE_INT;
- tmp = real_int::from_array
- (val, (w + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT, w);
- tmp = wi::lrshift (tmp, (words * HOST_BITS_PER_WIDE_INT) - exp);
- result = wide_int::from (tmp, precision, UNSIGNED);
+ /* Shift the value into place and truncate to the desired precision. */
+ result = wide_int::from_array (val, words, w);
+ result = wi::lrshift (result, w - exp);
+ result = wide_int::from (result, precision, UNSIGNED);
if (r->sign)
return -result;