re PR middle-end/30704 (Incorrect constant generation for long long)

PR middle-end/30704
	* fold-const.c (native_encode_real): Encode real.c provided longs
	as a series of 32-bit native integers.
	(native_interpret_real): Interpret buffer as a series of 32-bit
	native integers.

	* gcc.c-torture/execute/ieee/pr30704.c: New test.

From-SVN: r123455
This commit is contained in:
Jakub Jelinek 2007-04-03 11:05:38 +02:00 committed by Jakub Jelinek
parent eb9af792f2
commit 0a9430a831
4 changed files with 88 additions and 16 deletions

View File

@ -1,3 +1,11 @@
2007-04-03 Jakub Jelinek <jakub@redhat.com>
PR middle-end/30704
* fold-const.c (native_encode_real): Encode real.c provided longs
as a series of 32-bit native integers.
(native_interpret_real): Interpret buffer as a series of 32-bit
native integers.
2007-04-03 Richard Guenther <rguenther@suse.de>
* genpreds.c (write_insn_constraint_len): Write function

View File

@ -7162,7 +7162,7 @@ native_encode_real (tree expr, unsigned char *ptr, int len)
{
tree type = TREE_TYPE (expr);
int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
int byte, offset, word, words;
int byte, offset, word, words, bitpos;
unsigned char value;
/* There are always 32 bits in each long, no matter the size of
@ -7172,19 +7172,20 @@ native_encode_real (tree expr, unsigned char *ptr, int len)
if (total_bytes > len)
return 0;
words = total_bytes / UNITS_PER_WORD;
words = 32 / UNITS_PER_WORD;
real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
for (byte = 0; byte < total_bytes; byte++)
for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT;
bitpos += BITS_PER_UNIT)
{
int bitpos = byte * BITS_PER_UNIT;
byte = (bitpos / BITS_PER_UNIT) & 3;
value = (unsigned char) (tmp[bitpos / 32] >> (bitpos & 31));
if (total_bytes > UNITS_PER_WORD)
if (UNITS_PER_WORD < 4)
{
word = byte / UNITS_PER_WORD;
if (FLOAT_WORDS_BIG_ENDIAN)
if (WORDS_BIG_ENDIAN)
word = (words - 1) - word;
offset = word * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
@ -7193,8 +7194,8 @@ native_encode_real (tree expr, unsigned char *ptr, int len)
offset += byte % UNITS_PER_WORD;
}
else
offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
ptr[offset] = value;
offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)] = value;
}
return total_bytes;
}
@ -7350,7 +7351,7 @@ native_interpret_real (tree type, unsigned char *ptr, int len)
{
enum machine_mode mode = TYPE_MODE (type);
int total_bytes = GET_MODE_SIZE (mode);
int byte, offset, word, words;
int byte, offset, word, words, bitpos;
unsigned char value;
/* There are always 32 bits in each long, no matter the size of
the hosts long. We handle floating point representations with
@ -7361,16 +7362,17 @@ native_interpret_real (tree type, unsigned char *ptr, int len)
total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
if (total_bytes > len || total_bytes > 24)
return NULL_TREE;
words = total_bytes / UNITS_PER_WORD;
words = 32 / UNITS_PER_WORD;
memset (tmp, 0, sizeof (tmp));
for (byte = 0; byte < total_bytes; byte++)
for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT;
bitpos += BITS_PER_UNIT)
{
int bitpos = byte * BITS_PER_UNIT;
if (total_bytes > UNITS_PER_WORD)
byte = (bitpos / BITS_PER_UNIT) & 3;
if (UNITS_PER_WORD < 4)
{
word = byte / UNITS_PER_WORD;
if (FLOAT_WORDS_BIG_ENDIAN)
if (WORDS_BIG_ENDIAN)
word = (words - 1) - word;
offset = word * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
@ -7379,8 +7381,8 @@ native_interpret_real (tree type, unsigned char *ptr, int len)
offset += byte % UNITS_PER_WORD;
}
else
offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
value = ptr[offset];
offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
value = ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)];
tmp[bitpos / 32] |= (unsigned long)value << (bitpos & 31);
}

View File

@ -1,3 +1,8 @@
2007-04-03 Jakub Jelinek <jakub@redhat.com>
PR middle-end/30704
* gcc.c-torture/execute/ieee/pr30704.c: New test.
2007-04-02 Jason Merrill <jason@redhat.com>
PR c++/31187

View File

@ -0,0 +1,57 @@
/* PR middle-end/30704 */
typedef __SIZE_TYPE__ size_t;
extern void abort (void);
extern int memcmp (const void *, const void *, size_t);
extern void *memcpy (void *, const void *, size_t);
long long
__attribute__((noinline))
f1 (void)
{
long long t;
double d = 0x0.fffffffffffff000p-1022;
memcpy (&t, &d, sizeof (long long));
return t;
}
double
__attribute__((noinline))
f2 (void)
{
long long t = 0x000fedcba9876543LL;
double d;
memcpy (&d, &t, sizeof (long long));
return d;
}
int
main ()
{
union
{
long long ll;
double d;
} u;
if (sizeof (long long) != sizeof (double) || __DBL_MIN_EXP__ != -1021)
return 0;
u.ll = f1 ();
if (u.d != 0x0.fffffffffffff000p-1022)
abort ();
u.d = f2 ();
if (u.ll != 0x000fedcba9876543LL)
abort ();
double b = 234.0;
long long c;
double d = b;
memcpy (&c, &b, sizeof (double));
long long e = c;
if (memcmp (&e, &d, sizeof (double)) != 0)
abort ();
return 0;
}