This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] dfp.c fix for decimal float constants with LP64 host


Conversions within the compiler of decimal float values to integers,
and vice versa, were done via a memcpy of 32 bits from chunks of the
decimal float value to elements of an array of type long.  This worked
fine when the host was ILP32 but not when the host was LP64, leading
to invalid constants in the assembly code.  For powerpc64-linux the
constants were rejected by the assembler, so the effective-target test
for being able to run decimal float tests failed, making the tests in
gcc.dg/dfp compile-only and skipping the use of decimal float types in
the struct-layout-1 compatiblity tests.  On x86_64-linux positive
constants were OK, negative constants were incorrect.

This patch fixes the problem by using a memcpy into a 32-bit int and
then assigning that value (with sign-extension) into the long array
element.

Bootstrap and regression tested on powerpc64-linux, -m32 and -m64,
with compilers built as both 32-bit and 64-bit binaries, all
languages but Ada.  Bootstrapped C on i686-linux and x86_64-linux,
with --enable-decimal-float=bid and --enable-decimal-float=dpd,
and ran the gcc.dg/dfp tests, with no test regressions anywhere.
OK for trunk and open release branches?

2009-05-05  Janis Johnson  <janis187@us.ibm.com>

gcc/
	PR middle-end/39986
	* dfp.c (encode_decimal32, decode_decimal32, encode_decimal64,
	decode_decimal64, encode_decimal128, decode_decimal128): Avoid
	32-bit memcpy into long.

gcc/testsuite/
	PR middle-end/39986
	* gcc.dg/dfp/pr39986.c: New test.

Index: gcc/dfp.c
===================================================================
--- gcc/dfp.c	(revision 147035)
+++ gcc/dfp.c	(working copy)
@@ -133,6 +133,7 @@ encode_decimal32 (const struct real_form
   decNumber dn;
   decimal32 d32;
   decContext set;
+  int32_t image;
 
   decContextDefault (&set, DEC_INIT_DECIMAL128);
   set.traps = 0;
@@ -140,7 +141,8 @@ encode_decimal32 (const struct real_form
   decimal_to_decnumber (r, &dn); 
   decimal32FromNumber (&d32, &dn, &set);
 
-  memcpy (&buf[0], d32.bytes, sizeof (uint32_t));
+  memcpy (&image, d32.bytes, sizeof (int32_t));
+  buf[0] = image;
 }
 
 /* Decode an IEEE 754 decimal32 type into a real.  */
@@ -152,11 +154,13 @@ decode_decimal32 (const struct real_form
   decNumber dn;
   decimal32 d32;
   decContext set;
+  int32_t image;
 
   decContextDefault (&set, DEC_INIT_DECIMAL128);
   set.traps = 0;
 
-  memcpy (&d32.bytes, &buf[0], sizeof (uint32_t));
+  image = buf[0];
+  memcpy (&d32.bytes, &image, sizeof (int32_t));
 
   decimal32ToNumber (&d32, &dn);
   decimal_from_decnumber (r, &dn, &set); 
@@ -171,6 +175,7 @@ encode_decimal64 (const struct real_form
   decNumber dn;
   decimal64 d64;
   decContext set;
+  int32_t image;
 
   decContextDefault (&set, DEC_INIT_DECIMAL128);
   set.traps = 0;
@@ -180,13 +185,17 @@ encode_decimal64 (const struct real_form
 
   if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
     {
-      memcpy (&buf[0], &d64.bytes[0], sizeof (uint32_t));
-      memcpy (&buf[1], &d64.bytes[4], sizeof (uint32_t));
+      memcpy (&image, &d64.bytes[0], sizeof (int32_t));
+      buf[0] = image;
+      memcpy (&image, &d64.bytes[4], sizeof (int32_t));
+      buf[1] = image;
     }
   else
     {
-      memcpy (&buf[0], &d64.bytes[4], sizeof (uint32_t));
-      memcpy (&buf[1], &d64.bytes[0], sizeof (uint32_t));
+      memcpy (&image, &d64.bytes[4], sizeof (int32_t));
+      buf[0] = image;
+      memcpy (&image, &d64.bytes[0], sizeof (int32_t));
+      buf[1] = image;
     }
 }
 
@@ -199,19 +208,24 @@ decode_decimal64 (const struct real_form
   decNumber dn;
   decimal64 d64;
   decContext set;
+  int32_t image;
 
   decContextDefault (&set, DEC_INIT_DECIMAL128);
   set.traps = 0;
 
   if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
     {
-      memcpy (&d64.bytes[0], &buf[0], sizeof (uint32_t));
-      memcpy (&d64.bytes[4], &buf[1], sizeof (uint32_t));
+      image = buf[0];
+      memcpy (&d64.bytes[0], &image, sizeof (int32_t));
+      image = buf[1];
+      memcpy (&d64.bytes[4], &image, sizeof (int32_t));
     }
   else
     {
-      memcpy (&d64.bytes[0], &buf[1], sizeof (uint32_t));
-      memcpy (&d64.bytes[4], &buf[0], sizeof (uint32_t));
+      image = buf[1];
+      memcpy (&d64.bytes[0], &image, sizeof (int32_t));
+      image = buf[0];
+      memcpy (&d64.bytes[4], &image, sizeof (int32_t));
     }
 
   decimal64ToNumber (&d64, &dn);
@@ -227,6 +241,7 @@ encode_decimal128 (const struct real_for
   decNumber dn;
   decContext set;
   decimal128 d128;
+  int32_t image;
 
   decContextDefault (&set, DEC_INIT_DECIMAL128);
   set.traps = 0;
@@ -236,17 +251,25 @@ encode_decimal128 (const struct real_for
 
   if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
     {
-      memcpy (&buf[0], &d128.bytes[0], sizeof (uint32_t));
-      memcpy (&buf[1], &d128.bytes[4], sizeof (uint32_t));
-      memcpy (&buf[2], &d128.bytes[8], sizeof (uint32_t));
-      memcpy (&buf[3], &d128.bytes[12], sizeof (uint32_t));
+      memcpy (&image, &d128.bytes[0], sizeof (int32_t));
+      buf[0] = image;
+      memcpy (&image, &d128.bytes[4], sizeof (int32_t));
+      buf[1] = image;
+      memcpy (&image, &d128.bytes[8], sizeof (int32_t));
+      buf[2] = image;
+      memcpy (&image, &d128.bytes[12], sizeof (int32_t));
+      buf[3] = image;
     }
   else
     {
-      memcpy (&buf[0], &d128.bytes[12], sizeof (uint32_t));
-      memcpy (&buf[1], &d128.bytes[8], sizeof (uint32_t));
-      memcpy (&buf[2], &d128.bytes[4], sizeof (uint32_t));
-      memcpy (&buf[3], &d128.bytes[0], sizeof (uint32_t));
+      memcpy (&image, &d128.bytes[12], sizeof (int32_t));
+      buf[0] = image;
+      memcpy (&image, &d128.bytes[8], sizeof (int32_t));
+      buf[1] = image;
+      memcpy (&image, &d128.bytes[4], sizeof (int32_t));
+      buf[2] = image;
+      memcpy (&image, &d128.bytes[0], sizeof (int32_t));
+      buf[3] = image;
     }
 }
 
@@ -259,23 +282,32 @@ decode_decimal128 (const struct real_for
   decNumber dn;
   decimal128 d128;
   decContext set;
+  int32_t image;
 
   decContextDefault (&set, DEC_INIT_DECIMAL128);
   set.traps = 0;
 
   if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
     {
-      memcpy (&d128.bytes[0],  &buf[0], sizeof (uint32_t));
-      memcpy (&d128.bytes[4],  &buf[1], sizeof (uint32_t));
-      memcpy (&d128.bytes[8],  &buf[2], sizeof (uint32_t));
-      memcpy (&d128.bytes[12], &buf[3], sizeof (uint32_t));
+      image = buf[0];
+      memcpy (&d128.bytes[0],  &image, sizeof (int32_t));
+      image = buf[1];
+      memcpy (&d128.bytes[4],  &image, sizeof (int32_t));
+      image = buf[2];
+      memcpy (&d128.bytes[8],  &image, sizeof (int32_t));
+      image = buf[3];
+      memcpy (&d128.bytes[12], &image, sizeof (int32_t));
     }
   else
     {
-      memcpy (&d128.bytes[0],  &buf[3], sizeof (uint32_t));
-      memcpy (&d128.bytes[4],  &buf[2], sizeof (uint32_t));
-      memcpy (&d128.bytes[8],  &buf[1], sizeof (uint32_t));
-      memcpy (&d128.bytes[12], &buf[0], sizeof (uint32_t));
+      image = buf[3];
+      memcpy (&d128.bytes[0],  &image, sizeof (int32_t));
+      image = buf[2];
+      memcpy (&d128.bytes[4],  &image, sizeof (int32_t));
+      image = buf[1];
+      memcpy (&d128.bytes[8],  &image, sizeof (int32_t));
+      image = buf[0];
+      memcpy (&d128.bytes[12], &image, sizeof (int32_t));
     }
 
   decimal128ToNumber (&d128, &dn);
Index: gcc/testsuite/gcc.dg/dfp/pr39986.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pr39986.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pr39986.c	(revision 0)
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+/* Check that the compiler generates the correct decimal float constants.  */
+
+_Decimal32 a = 100.223df;
+_Decimal32 b = -2.3df;
+_Decimal64 c = 3.4e-4dd;
+_Decimal64 d = -4.500dd;
+_Decimal128 e = 5678901234567.89e+200dl;
+_Decimal128 f = -678901.234e-6dl;
+
+/* The first value is DPD, the second is BID.  The order differs depending
+   on whether the target is big-endian or little-endian.  */
+
+/* { dg-final { scan-assembler ".long\t(572653859|822183807)\n" } } */
+
+/* { dg-final { scan-assembler ".long\t(-1572863965|-1308622825)\n" } } */
+
+/* { dg-final { scan-assembler ".long\t(52|34)\n" } } */
+/* { dg-final { scan-assembler ".long\t(572784640|824180736)\n" } } */
+
+/* { dg-final { scan-assembler ".long\t(4736|4500)\n" } } */
+/* { dg-final { scan-assembler ".long\t(-1574174720|-1319108608)\n" } } */
+
+/* { dg-final { scan-assembler ".long\t(-1975952433|957645077)\n" } } */
+/* { dg-final { scan-assembler ".long\t(190215|132222)\n" } } */
+/* { dg-final { scan-assembler ".long\t(574193664|835452928)\n" } } */
+
+/* { dg-final { scan-assembler ".long\t(931280180|678901234)\n" } } */
+/* { dg-final { scan-assembler ".long\t(-1576681472|-1339162624)\n" } } */



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]