/* Decimal floating point support.
- Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2005-2020 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
-#include "toplev.h"
-#include "real.h"
-#include "tm_p.h"
#include "dfp.h"
/* The order of the following headers is important for making sure
#include "decimal128.h"
#include "decimal64.h"
#include "decimal32.h"
-#include "decNumber.h"
-static uint32_t
-dfp_byte_swap (uint32_t in)
-{
- uint32_t out = 0;
- unsigned char *p = (unsigned char *) &out;
- union {
- uint32_t i;
- unsigned char b[4];
- } u;
-
- u.i = in;
- p[0] = u.b[3];
- p[1] = u.b[2];
- p[2] = u.b[1];
- p[3] = u.b[0];
-
- return out;
-}
+#ifndef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN 0
+#endif
/* Initialize R (a real with the decimal flag set) from DN. Can
utilize status passed in via CONTEXT, if a previous operation had
memset (r, 0, sizeof (REAL_VALUE_TYPE));
r->cl = rvc_normal;
- if (decNumberIsZero (dn))
- r->cl = rvc_zero;
if (decNumberIsNaN (dn))
r->cl = rvc_nan;
if (decNumberIsInfinite (dn))
decNumberFromString (dn, "nan", &set);
break;
case rvc_normal:
- gcc_assert (r->decimal);
+ if (!r->decimal)
+ {
+ /* dconst{1,2,m1,half} are used in various places in
+ the middle-end and optimizers, allow them here
+ as an exception by converting them to decimal. */
+ if (memcmp (r, &dconst1, sizeof (*r)) == 0)
+ {
+ decNumberFromString (dn, "1", &set);
+ break;
+ }
+ if (memcmp (r, &dconst2, sizeof (*r)) == 0)
+ {
+ decNumberFromString (dn, "2", &set);
+ break;
+ }
+ if (memcmp (r, &dconstm1, sizeof (*r)) == 0)
+ {
+ decNumberFromString (dn, "-1", &set);
+ break;
+ }
+ if (memcmp (r, &dconsthalf, sizeof (*r)) == 0)
+ {
+ decNumberFromString (dn, "0.5", &set);
+ break;
+ }
+ gcc_unreachable ();
+ }
decimal128ToNumber ((const decimal128 *) r->sig, dn);
break;
default:
dn->bits ^= DECNEG;
}
-/* Encode a real into an IEEE 754R decimal32 type. */
+/* Encode a real into an IEEE 754 decimal32 type. */
void
encode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED,
decNumber dn;
decimal32 d32;
decContext set;
+ int32_t image;
decContextDefault (&set, DEC_INIT_DECIMAL128);
set.traps = 0;
- decimal_to_decnumber (r, &dn);
+ decimal_to_decnumber (r, &dn);
decimal32FromNumber (&d32, &dn, &set);
- if (FLOAT_WORDS_BIG_ENDIAN)
- buf[0] = *(uint32_t *) d32.bytes;
- else
- buf[0] = dfp_byte_swap (*(uint32_t *) d32.bytes);
+ memcpy (&image, d32.bytes, sizeof (int32_t));
+ buf[0] = image;
}
-/* Decode an IEEE 754R decimal32 type into a real. */
+/* Decode an IEEE 754 decimal32 type into a real. */
void
decode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED,
decNumber dn;
decimal32 d32;
decContext set;
+ int32_t image;
decContextDefault (&set, DEC_INIT_DECIMAL128);
set.traps = 0;
- if (FLOAT_WORDS_BIG_ENDIAN)
- *((uint32_t *) d32.bytes) = (uint32_t) buf[0];
- else
- *((uint32_t *) d32.bytes) = dfp_byte_swap ((uint32_t) buf[0]);
+ image = buf[0];
+ memcpy (&d32.bytes, &image, sizeof (int32_t));
decimal32ToNumber (&d32, &dn);
- decimal_from_decnumber (r, &dn, &set);
+ decimal_from_decnumber (r, &dn, &set);
}
-/* Encode a real into an IEEE 754R decimal64 type. */
+/* Encode a real into an IEEE 754 decimal64 type. */
void
encode_decimal64 (const struct real_format *fmt ATTRIBUTE_UNUSED,
decNumber dn;
decimal64 d64;
decContext set;
+ int32_t image;
decContextDefault (&set, DEC_INIT_DECIMAL128);
set.traps = 0;
decimal_to_decnumber (r, &dn);
decimal64FromNumber (&d64, &dn, &set);
- if (FLOAT_WORDS_BIG_ENDIAN)
+ if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
{
- buf[0] = *(uint32_t *) &d64.bytes[0];
- buf[1] = *(uint32_t *) &d64.bytes[4];
+ memcpy (&image, &d64.bytes[0], sizeof (int32_t));
+ buf[0] = image;
+ memcpy (&image, &d64.bytes[4], sizeof (int32_t));
+ buf[1] = image;
}
else
{
- buf[1] = dfp_byte_swap (*(uint32_t *) &d64.bytes[0]);
- buf[0] = dfp_byte_swap (*(uint32_t *) &d64.bytes[4]);
+ memcpy (&image, &d64.bytes[4], sizeof (int32_t));
+ buf[0] = image;
+ memcpy (&image, &d64.bytes[0], sizeof (int32_t));
+ buf[1] = image;
}
}
-/* Decode an IEEE 754R decimal64 type into a real. */
+/* Decode an IEEE 754 decimal64 type into a real. */
void
decode_decimal64 (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
-{
+{
decNumber dn;
decimal64 d64;
decContext set;
+ int32_t image;
decContextDefault (&set, DEC_INIT_DECIMAL128);
set.traps = 0;
- if (FLOAT_WORDS_BIG_ENDIAN)
+ if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
{
- *((uint32_t *) &d64.bytes[0]) = (uint32_t) buf[0];
- *((uint32_t *) &d64.bytes[4]) = (uint32_t) buf[1];
+ image = buf[0];
+ memcpy (&d64.bytes[0], &image, sizeof (int32_t));
+ image = buf[1];
+ memcpy (&d64.bytes[4], &image, sizeof (int32_t));
}
else
{
- *((uint32_t *) &d64.bytes[0]) = dfp_byte_swap ((uint32_t) buf[1]);
- *((uint32_t *) &d64.bytes[4]) = dfp_byte_swap ((uint32_t) buf[0]);
+ 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);
- decimal_from_decnumber (r, &dn, &set);
+ decimal_from_decnumber (r, &dn, &set);
}
-/* Encode a real into an IEEE 754R decimal128 type. */
+/* Encode a real into an IEEE 754 decimal128 type. */
void
encode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED,
decNumber dn;
decContext set;
decimal128 d128;
+ int32_t image;
decContextDefault (&set, DEC_INIT_DECIMAL128);
set.traps = 0;
decimal_to_decnumber (r, &dn);
decimal128FromNumber (&d128, &dn, &set);
- if (FLOAT_WORDS_BIG_ENDIAN)
+ if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
{
- buf[0] = *(uint32_t *) &d128.bytes[0];
- buf[1] = *(uint32_t *) &d128.bytes[4];
- buf[2] = *(uint32_t *) &d128.bytes[8];
- buf[3] = *(uint32_t *) &d128.bytes[12];
+ 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
{
- buf[0] = dfp_byte_swap (*(uint32_t *) &d128.bytes[12]);
- buf[1] = dfp_byte_swap (*(uint32_t *) &d128.bytes[8]);
- buf[2] = dfp_byte_swap (*(uint32_t *) &d128.bytes[4]);
- buf[3] = dfp_byte_swap (*(uint32_t *) &d128.bytes[0]);
+ 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;
}
}
-/* Decode an IEEE 754R decimal128 type into a real. */
+/* Decode an IEEE 754 decimal128 type into a real. */
void
decode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED,
decNumber dn;
decimal128 d128;
decContext set;
+ int32_t image;
decContextDefault (&set, DEC_INIT_DECIMAL128);
set.traps = 0;
- if (FLOAT_WORDS_BIG_ENDIAN)
+ if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
{
- *((uint32_t *) &d128.bytes[0]) = (uint32_t) buf[0];
- *((uint32_t *) &d128.bytes[4]) = (uint32_t) buf[1];
- *((uint32_t *) &d128.bytes[8]) = (uint32_t) buf[2];
- *((uint32_t *) &d128.bytes[12]) = (uint32_t) buf[3];
+ 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
{
- *((uint32_t *) &d128.bytes[0]) = dfp_byte_swap ((uint32_t) buf[3]);
- *((uint32_t *) &d128.bytes[4]) = dfp_byte_swap ((uint32_t) buf[2]);
- *((uint32_t *) &d128.bytes[8]) = dfp_byte_swap ((uint32_t) buf[1]);
- *((uint32_t *) &d128.bytes[12]) = dfp_byte_swap ((uint32_t) buf[0]);
+ 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);
- decimal_from_decnumber (r, &dn, &set);
+ decimal_from_decnumber (r, &dn, &set);
}
/* Helper function to convert from a binary real internal
static void
decimal_to_binary (REAL_VALUE_TYPE *to, const REAL_VALUE_TYPE *from,
- enum machine_mode mode)
+ const real_format *fmt)
{
char string[256];
- const decimal128 *const d128 = (const decimal128 *) from->sig;
-
- decimal128ToString (d128, string);
- real_from_string3 (to, string, mode);
+ if (from->cl == rvc_normal)
+ {
+ const decimal128 *const d128 = (const decimal128 *) from->sig;
+ decimal128ToString (d128, string);
+ }
+ else
+ real_to_decimal (string, from, sizeof (string), 0, 1);
+ real_from_string3 (to, string, fmt);
}
decimal_from_binary (&b1, b);
b = &b1;
}
-
+
/* Convert into decNumber form for comparison operation. */
decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
+ set.traps = 0;
decimal128ToNumber ((const decimal128 *) a->sig, &dn2);
decimal128ToNumber ((const decimal128 *) b->sig, &dn3);
return 0;
else if (decNumberIsNegative (&dn))
return -1;
- else
+ else
return 1;
}
binary and decimal types. */
void
-decimal_real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode,
+decimal_real_convert (REAL_VALUE_TYPE *r, const real_format *fmt,
const REAL_VALUE_TYPE *a)
{
- const struct real_format *fmt = REAL_MODE_FORMAT (mode);
-
if (a->decimal && fmt->b == 10)
return;
if (a->decimal)
- decimal_to_binary (r, a, mode);
+ decimal_to_binary (r, a, fmt);
else
decimal_from_binary (r, a);
}
if (subtract_p)
decNumberSubtract (&dn, &dn2, &dn3, &set);
- else
+ else
decNumberAdd (&dn, &dn2, &dn3, &set);
decimal_from_decnumber (r, &dn, &set);
return real_to_integer (&to);
}
-/* Likewise, but to an integer pair, HI+LOW. */
+/* Likewise, but returns a wide_int with PRECISION. *FAIL is set if the
+ value does not fit. */
-void
-decimal_real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
- const REAL_VALUE_TYPE *r)
+wide_int
+decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
{
decContext set;
decNumber dn, dn2, dn3;
decNumberZero (&dn3);
decNumberRescale (&dn, &dn2, &dn3, &set);
- /* Conver to REAL_VALUE_TYPE and call appropriate conversion
+ /* Convert to REAL_VALUE_TYPE and call appropriate conversion
function. */
decNumberToString (&dn, string);
real_from_string (&to, string);
- real_to_integer2 (plow, phigh, &to);
+ return real_to_integer (&to, fail, precision);
}
/* Perform the decimal floating point operation described by CODE.
If SIGN is nonzero, R is set to the most negative finite value. */
void
-decimal_real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
-{
+decimal_real_maxval (REAL_VALUE_TYPE *r, int sign, machine_mode mode)
+{
const char *max;
switch (mode)
{
- case SDmode:
+ case E_SDmode:
max = "9.999999E96";
break;
- case DDmode:
+ case E_DDmode:
max = "9.999999999999999E384";
break;
- case TDmode:
+ case E_TDmode:
max = "9.999999999999999999999999999999999E6144";
break;
default: