123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- /* Decimal floating point support.
- Copyright (C) 2005-2015 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 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- 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 "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "real.h"
- #include "tree.h"
- #include "tm_p.h"
- #include "dfp.h"
- #include "wide-int.h"
- /* The order of the following headers is important for making sure
- decNumber structure is large enough to hold decimal128 digits. */
- #include "decimal128.h"
- #include "decimal128Local.h"
- #include "decimal64.h"
- #include "decimal32.h"
- #include "decNumber.h"
- #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
- interesting status. */
- static void
- decimal_from_decnumber (REAL_VALUE_TYPE *r, decNumber *dn, decContext *context)
- {
- memset (r, 0, sizeof (REAL_VALUE_TYPE));
- r->cl = rvc_normal;
- if (decNumberIsNaN (dn))
- r->cl = rvc_nan;
- if (decNumberIsInfinite (dn))
- r->cl = rvc_inf;
- if (context->status & DEC_Overflow)
- r->cl = rvc_inf;
- if (decNumberIsNegative (dn))
- r->sign = 1;
- r->decimal = 1;
- if (r->cl != rvc_normal)
- return;
- decContextDefault (context, DEC_INIT_DECIMAL128);
- context->traps = 0;
- decimal128FromNumber ((decimal128 *) r->sig, dn, context);
- }
- /* Create decimal encoded R from string S. */
- void
- decimal_real_from_string (REAL_VALUE_TYPE *r, const char *s)
- {
- decNumber dn;
- decContext set;
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- decNumberFromString (&dn, s, &set);
- /* It would be more efficient to store directly in decNumber format,
- but that is impractical from current data structure size.
- Encoding as a decimal128 is much more compact. */
- decimal_from_decnumber (r, &dn, &set);
- }
- /* Initialize a decNumber from a REAL_VALUE_TYPE. */
- static void
- decimal_to_decnumber (const REAL_VALUE_TYPE *r, decNumber *dn)
- {
- decContext set;
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- switch (r->cl)
- {
- case rvc_zero:
- decNumberZero (dn);
- break;
- case rvc_inf:
- decNumberFromString (dn, "Infinity", &set);
- break;
- case rvc_nan:
- if (r->signalling)
- decNumberFromString (dn, "snan", &set);
- else
- decNumberFromString (dn, "nan", &set);
- break;
- case rvc_normal:
- 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:
- gcc_unreachable ();
- }
- /* Fix up sign bit. */
- if (r->sign != decNumberIsNegative (dn))
- dn->bits ^= DECNEG;
- }
- /* Encode a real into an IEEE 754 decimal32 type. */
- void
- encode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED,
- long *buf, const REAL_VALUE_TYPE *r)
- {
- decNumber dn;
- decimal32 d32;
- decContext set;
- int32_t image;
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- decimal_to_decnumber (r, &dn);
- decimal32FromNumber (&d32, &dn, &set);
- memcpy (&image, d32.bytes, sizeof (int32_t));
- buf[0] = image;
- }
- /* Decode an IEEE 754 decimal32 type into a real. */
- void
- decode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED,
- REAL_VALUE_TYPE *r, const long *buf)
- {
- decNumber dn;
- decimal32 d32;
- decContext set;
- int32_t image;
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- image = buf[0];
- memcpy (&d32.bytes, &image, sizeof (int32_t));
- decimal32ToNumber (&d32, &dn);
- decimal_from_decnumber (r, &dn, &set);
- }
- /* Encode a real into an IEEE 754 decimal64 type. */
- void
- encode_decimal64 (const struct real_format *fmt ATTRIBUTE_UNUSED,
- long *buf, const REAL_VALUE_TYPE *r)
- {
- 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 (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
- {
- memcpy (&image, &d64.bytes[0], sizeof (int32_t));
- buf[0] = image;
- memcpy (&image, &d64.bytes[4], sizeof (int32_t));
- buf[1] = image;
- }
- else
- {
- 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 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 (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
- {
- image = buf[0];
- memcpy (&d64.bytes[0], &image, sizeof (int32_t));
- image = buf[1];
- memcpy (&d64.bytes[4], &image, sizeof (int32_t));
- }
- else
- {
- 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);
- }
- /* Encode a real into an IEEE 754 decimal128 type. */
- void
- encode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED,
- long *buf, const REAL_VALUE_TYPE *r)
- {
- 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 (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
- {
- 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 (&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 754 decimal128 type into a real. */
- void
- decode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED,
- REAL_VALUE_TYPE *r, const long *buf)
- {
- decNumber dn;
- decimal128 d128;
- decContext set;
- int32_t image;
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- if (WORDS_BIGENDIAN == FLOAT_WORDS_BIG_ENDIAN)
- {
- 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
- {
- 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);
- }
- /* Helper function to convert from a binary real internal
- representation. */
- static void
- decimal_to_binary (REAL_VALUE_TYPE *to, const REAL_VALUE_TYPE *from,
- machine_mode mode)
- {
- char string[256];
- const decimal128 *const d128 = (const decimal128 *) from->sig;
- decimal128ToString (d128, string);
- real_from_string3 (to, string, mode);
- }
- /* Helper function to convert from a binary real internal
- representation. */
- static void
- decimal_from_binary (REAL_VALUE_TYPE *to, const REAL_VALUE_TYPE *from)
- {
- char string[256];
- /* We convert to string, then to decNumber then to decimal128. */
- real_to_decimal (string, from, sizeof (string), 0, 1);
- decimal_real_from_string (to, string);
- }
- /* Helper function to real.c:do_compare() to handle decimal internal
- representation including when one of the operands is still in the
- binary internal representation. */
- int
- decimal_do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b,
- int nan_result)
- {
- decContext set;
- decNumber dn, dn2, dn3;
- REAL_VALUE_TYPE a1, b1;
- /* If either operand is non-decimal, create temporary versions. */
- if (!a->decimal)
- {
- decimal_from_binary (&a1, a);
- a = &a1;
- }
- if (!b->decimal)
- {
- decimal_from_binary (&b1, b);
- b = &b1;
- }
- /* Convert into decNumber form for comparison operation. */
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- decimal128ToNumber ((const decimal128 *) a->sig, &dn2);
- decimal128ToNumber ((const decimal128 *) b->sig, &dn3);
- /* Finally, do the comparison. */
- decNumberCompare (&dn, &dn2, &dn3, &set);
- /* Return the comparison result. */
- if (decNumberIsNaN (&dn))
- return nan_result;
- else if (decNumberIsZero (&dn))
- return 0;
- else if (decNumberIsNegative (&dn))
- return -1;
- else
- return 1;
- }
- /* Helper to round_for_format, handling decimal float types. */
- void
- decimal_round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
- {
- decNumber dn;
- decContext set;
- /* Real encoding occurs later. */
- if (r->cl != rvc_normal)
- return;
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- decimal128ToNumber ((decimal128 *) r->sig, &dn);
- if (fmt == &decimal_quad_format)
- {
- /* The internal format is already in this format. */
- return;
- }
- else if (fmt == &decimal_single_format)
- {
- decimal32 d32;
- decContextDefault (&set, DEC_INIT_DECIMAL32);
- set.traps = 0;
- decimal32FromNumber (&d32, &dn, &set);
- decimal32ToNumber (&d32, &dn);
- }
- else if (fmt == &decimal_double_format)
- {
- decimal64 d64;
- decContextDefault (&set, DEC_INIT_DECIMAL64);
- set.traps = 0;
- decimal64FromNumber (&d64, &dn, &set);
- decimal64ToNumber (&d64, &dn);
- }
- else
- gcc_unreachable ();
- decimal_from_decnumber (r, &dn, &set);
- }
- /* Extend or truncate to a new mode. Handles conversions between
- binary and decimal types. */
- void
- decimal_real_convert (REAL_VALUE_TYPE *r, machine_mode mode,
- 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);
- else
- decimal_from_binary (r, a);
- }
- /* Render R_ORIG as a decimal floating point constant. Emit DIGITS
- significant digits in the result, bounded by BUF_SIZE. If DIGITS
- is 0, choose the maximum for the representation. If
- CROP_TRAILING_ZEROS, strip trailing zeros. Currently, not honoring
- DIGITS or CROP_TRAILING_ZEROS. */
- void
- decimal_real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig,
- size_t buf_size,
- size_t digits ATTRIBUTE_UNUSED,
- int crop_trailing_zeros ATTRIBUTE_UNUSED)
- {
- const decimal128 *const d128 = (const decimal128*) r_orig->sig;
- /* decimal128ToString requires space for at least 24 characters;
- Require two more for suffix. */
- gcc_assert (buf_size >= 24);
- decimal128ToString (d128, str);
- }
- static bool
- decimal_do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0,
- const REAL_VALUE_TYPE *op1, int subtract_p)
- {
- decNumber dn;
- decContext set;
- decNumber dn2, dn3;
- decimal_to_decnumber (op0, &dn2);
- decimal_to_decnumber (op1, &dn3);
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- if (subtract_p)
- decNumberSubtract (&dn, &dn2, &dn3, &set);
- else
- decNumberAdd (&dn, &dn2, &dn3, &set);
- decimal_from_decnumber (r, &dn, &set);
- /* Return true, if inexact. */
- return (set.status & DEC_Inexact);
- }
- /* Compute R = OP0 * OP1. */
- static bool
- decimal_do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0,
- const REAL_VALUE_TYPE *op1)
- {
- decContext set;
- decNumber dn, dn2, dn3;
- decimal_to_decnumber (op0, &dn2);
- decimal_to_decnumber (op1, &dn3);
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- decNumberMultiply (&dn, &dn2, &dn3, &set);
- decimal_from_decnumber (r, &dn, &set);
- /* Return true, if inexact. */
- return (set.status & DEC_Inexact);
- }
- /* Compute R = OP0 / OP1. */
- static bool
- decimal_do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0,
- const REAL_VALUE_TYPE *op1)
- {
- decContext set;
- decNumber dn, dn2, dn3;
- decimal_to_decnumber (op0, &dn2);
- decimal_to_decnumber (op1, &dn3);
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- decNumberDivide (&dn, &dn2, &dn3, &set);
- decimal_from_decnumber (r, &dn, &set);
- /* Return true, if inexact. */
- return (set.status & DEC_Inexact);
- }
- /* Set R to A truncated to an integral value toward zero (decimal
- floating point). */
- void
- decimal_do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
- {
- decNumber dn, dn2;
- decContext set;
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- set.round = DEC_ROUND_DOWN;
- decimal128ToNumber ((const decimal128 *) a->sig, &dn2);
- decNumberToIntegralValue (&dn, &dn2, &set);
- decimal_from_decnumber (r, &dn, &set);
- }
- /* Render decimal float value R as an integer. */
- HOST_WIDE_INT
- decimal_real_to_integer (const REAL_VALUE_TYPE *r)
- {
- decContext set;
- decNumber dn, dn2, dn3;
- REAL_VALUE_TYPE to;
- char string[256];
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- set.round = DEC_ROUND_DOWN;
- decimal128ToNumber ((const decimal128 *) r->sig, &dn);
- decNumberToIntegralValue (&dn2, &dn, &set);
- decNumberZero (&dn3);
- decNumberRescale (&dn, &dn2, &dn3, &set);
- /* Convert to REAL_VALUE_TYPE and call appropriate conversion
- function. */
- decNumberToString (&dn, string);
- real_from_string (&to, string);
- return real_to_integer (&to);
- }
- /* Likewise, but returns a wide_int with PRECISION. *FAIL is set if the
- value does not fit. */
- wide_int
- decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
- {
- decContext set;
- decNumber dn, dn2, dn3;
- REAL_VALUE_TYPE to;
- char string[256];
- decContextDefault (&set, DEC_INIT_DECIMAL128);
- set.traps = 0;
- set.round = DEC_ROUND_DOWN;
- decimal128ToNumber ((const decimal128 *) r->sig, &dn);
- decNumberToIntegralValue (&dn2, &dn, &set);
- decNumberZero (&dn3);
- decNumberRescale (&dn, &dn2, &dn3, &set);
- /* Convert to REAL_VALUE_TYPE and call appropriate conversion
- function. */
- decNumberToString (&dn, string);
- real_from_string (&to, string);
- return real_to_integer (&to, fail, precision);
- }
- /* Perform the decimal floating point operation described by CODE.
- For a unary operation, OP1 will be NULL. This function returns
- true if the result may be inexact due to loss of precision. */
- bool
- decimal_real_arithmetic (REAL_VALUE_TYPE *r, enum tree_code code,
- const REAL_VALUE_TYPE *op0,
- const REAL_VALUE_TYPE *op1)
- {
- REAL_VALUE_TYPE a, b;
- /* If either operand is non-decimal, create temporaries. */
- if (!op0->decimal)
- {
- decimal_from_binary (&a, op0);
- op0 = &a;
- }
- if (op1 && !op1->decimal)
- {
- decimal_from_binary (&b, op1);
- op1 = &b;
- }
- switch (code)
- {
- case PLUS_EXPR:
- return decimal_do_add (r, op0, op1, 0);
- case MINUS_EXPR:
- return decimal_do_add (r, op0, op1, 1);
- case MULT_EXPR:
- return decimal_do_multiply (r, op0, op1);
- case RDIV_EXPR:
- return decimal_do_divide (r, op0, op1);
- case MIN_EXPR:
- if (op1->cl == rvc_nan)
- *r = *op1;
- else if (real_compare (UNLT_EXPR, op0, op1))
- *r = *op0;
- else
- *r = *op1;
- return false;
- case MAX_EXPR:
- if (op1->cl == rvc_nan)
- *r = *op1;
- else if (real_compare (LT_EXPR, op0, op1))
- *r = *op1;
- else
- *r = *op0;
- return false;
- case NEGATE_EXPR:
- {
- *r = *op0;
- /* Flip sign bit. */
- decimal128FlipSign ((decimal128 *) r->sig);
- /* Keep sign field in sync. */
- r->sign ^= 1;
- }
- return false;
- case ABS_EXPR:
- {
- *r = *op0;
- /* Clear sign bit. */
- decimal128ClearSign ((decimal128 *) r->sig);
- /* Keep sign field in sync. */
- r->sign = 0;
- }
- return false;
- case FIX_TRUNC_EXPR:
- decimal_do_fix_trunc (r, op0);
- return false;
- default:
- gcc_unreachable ();
- }
- }
- /* Fills R with the largest finite value representable in mode MODE.
- If SIGN is nonzero, R is set to the most negative finite value. */
- void
- decimal_real_maxval (REAL_VALUE_TYPE *r, int sign, machine_mode mode)
- {
- const char *max;
- switch (mode)
- {
- case SDmode:
- max = "9.999999E96";
- break;
- case DDmode:
- max = "9.999999999999999E384";
- break;
- case TDmode:
- max = "9.999999999999999999999999999999999E6144";
- break;
- default:
- gcc_unreachable ();
- }
- decimal_real_from_string (r, max);
- if (sign)
- decimal128SetSign ((decimal128 *) r->sig, 1);
- }
|