diff options
author | Jon Grimm <jgrimm2@us.ibm.com> | 2005-12-02 02:30:42 +0000 |
---|---|---|
committer | Ben Elliston <bje@gcc.gnu.org> | 2005-12-02 13:30:42 +1100 |
commit | 909e2256221436f25d53bd2fec7cf85634cdb8ec (patch) | |
tree | 50f43816a8c573b7d0fa0fd8a2d390dce801a672 /gcc/dfp.c | |
parent | 8da15291d0387b0391e4842e841561d63ea636de (diff) | |
download | gcc-909e2256221436f25d53bd2fec7cf85634cdb8ec.zip gcc-909e2256221436f25d53bd2fec7cf85634cdb8ec.tar.gz gcc-909e2256221436f25d53bd2fec7cf85634cdb8ec.tar.bz2 |
dfp.h, dfp.c: New files.
2005-12-02 Jon Grimm <jgrimm2@us.ibm.com>
Janis Johnson <janis187@us.ibm.com>
David Edelsohn <dje@watson.ibm.com>
Ben Elliston <bje@au.ibm.com>
* dfp.h, dfp.c: New files.
* Makefile.in (DECNUM, DECNUMINC, LIBDECNUMBER): New variables.
(DECNUM_H): Likewise.
(LIBDEPS, LIBS, BACKEND): Append $(LIBDECNUMBER).
(INCLUDES): Append $(DECNUMINC).
(OBJS-common): Add dfp.o.
(dfp.o): New rule.
* real.h (EXP_BITS): Pinch one bit to ..
(struct real_value): Add decimal field.
(real_format): Change table size, update documentation.
(REAL_MODE_FORMAT): Update for to handle float, decimal float.
(real_from_string3): Declare.
(decimal_single_format): Declare.
(decimal_double_format): Declare.
(decimal_quad_format): Declare.
(REAL_VALUE_TO_TARGET_DECIMAL32): New.
(REAL_VALUE_TO_TARGET_DECIMAL64): New.
(REAL_VALUE_TO_TARGET_DECIMAL128): New.
* real.c: Include dfp.h.
(normalize): Early return for decimal floats.
(do_add): Zero decimal field.
(do_compare): Call do_decimal_compare for decimal floats.
(do_fix_trunc): Likewise, call decimal_do_fix_trunc.
(real_arithmetic): Call decimal_real_arithmetic for decimal
floating point operands.
(real_identical): If a and b are of differing radix, return false.
(real_to_integer): Call decimal_real_to_integer if the value is a
decimal float.
(real_to_integer2): Likewise, call decimal_real_to_integer2.
(real_to_decimal): Likewise, call decimal_real_to_decimal.
(real_to_hexadecimal): Place "N/A" in the return string for
decimal float.
(real_from_string3): New variant, given a mode.
(real_maxval): Use decimal_real_maxval for decimal floats.
(round_for_format): Use decimal_round_for_format for decimals.
(real_convert): Use decimal_real_convert where appropriate.
(significand_size): Handle base 10.
(encode_decimal_single, decode_decimal_single,
encode_decimal_double, decode_decimal_double, encode_decimal_quad,
decode_decimal_quad): New functions.
(decimal_single_format): New.
(decimal_double_format): New.
(decimal_quad_format): New.
* machmode.def: Add SD, DD and TD decimal floating point modes.
* machmode.h (FLOAT_MODE_P, SCALAR_FLOAT_MODE_P, MODES_WIDEN_P):
Include MODE_DECIMAL_FLOAT.
(DECIMAL_FLOAT_MODE_P): New.
* mode-classes.def (MODE_DECIMAL_FLOAT): New mode class.
* genmodes.c (struct mode_data): Add counter field.
(struct mode_data): Update comment for format.
(blank_mode): Initialise counter field.
(new_mode): Increment counter field for each mode defined.
(complete_mode): Handle MODE_DECIMAL_FLOAT, update check for mode
using a format.
(make_complex_modes): Handle modes containing `D'.
(DECIMAL_FLOAT_MODE, FRACTIONAL_DECIMAL_FLOAT_MODE): New.
(make_decimal_float_mode): New.
(reset_float_format): Handle MODE_DECIMAL_FLOAT.
(cmp_modes): Compare counter field if other characteristics
similar.
(emit_real_format_for_mode): Support formats for decimal floats.
* doc/rtl.texi (Machine Modes): Document SD, DD and TDmodes.
Document MODE_DECIMAL_FLOAT.
Co-Authored-By: Ben Elliston <bje@au.ibm.com>
Co-Authored-By: David Edelsohn <dje@watson.ibm.com>
Co-Authored-By: Janis Johnson <janis187@us.ibm.com>
From-SVN: r107861
Diffstat (limited to 'gcc/dfp.c')
-rw-r--r-- | gcc/dfp.c | 725 |
1 files changed, 725 insertions, 0 deletions
diff --git a/gcc/dfp.c b/gcc/dfp.c new file mode 100644 index 0000000..ab05751 --- /dev/null +++ b/gcc/dfp.c @@ -0,0 +1,725 @@ +/* Decimal floating point support. + Copyright (C) 2005 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 +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 COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#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 + decNumber structure is large enough to hold decimal128 digits. */ + +#include "decimal128.h" +#include "decimal64.h" +#include "decimal32.h" +#include "decNumber.h" + +static unsigned long +dfp_byte_swap (unsigned long in) +{ + unsigned long out; + unsigned char *p = (unsigned char *) &out; + union { + unsigned long 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; +} + +/* 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 (decNumberIsZero (dn)) + r->cl = rvc_zero; + 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, (char *) 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, (char *)"Infinity", &set); + break; + case rvc_nan: + if (r->signalling) + decNumberFromString (dn, (char *)"snan", &set); + else + decNumberFromString (dn, (char *)"nan", &set); + break; + case rvc_normal: + gcc_assert (r->decimal); + decimal128ToNumber ((decimal128 *) r->sig, dn); + break; + default: + gcc_unreachable (); + } + + /* Fix up sign bit. */ + if (r->sign != decNumberIsNegative (dn)) + decNumberNegate (dn); +} + +/* Encode a real into an IEEE 754R 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; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + 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); +} + +/* Decode an IEEE 754R 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; + + 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]); + + decimal32ToNumber (&d32, &dn); + decimal_from_decnumber (r, &dn, &set); +} + +/* Encode a real into an IEEE 754R 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; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decimal_to_decnumber (r, &dn); + decimal64FromNumber (&d64, &dn, &set); + + if (FLOAT_WORDS_BIG_ENDIAN) + { + buf[0] = *(uint32_t *) &d64.bytes[0]; + buf[1] = *(uint32_t *) &d64.bytes[4]; + } + else + { + buf[1] = dfp_byte_swap (*(uint32_t *) &d64.bytes[0]); + buf[0] = dfp_byte_swap (*(uint32_t *) &d64.bytes[4]); + } +} + +/* Decode an IEEE 754R 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; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + if (FLOAT_WORDS_BIG_ENDIAN) + { + *((uint32_t *) &d64.bytes[0]) = (uint32_t) buf[0]; + *((uint32_t *) &d64.bytes[4]) = (uint32_t) buf[1]; + } + 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]); + } + + decimal64ToNumber (&d64, &dn); + decimal_from_decnumber (r, &dn, &set); +} + +/* Encode a real into an IEEE 754R 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; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decimal_to_decnumber (r, &dn); + decimal128FromNumber (&d128, &dn, &set); + + if (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]; + } + 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]); + } +} + +/* Decode an IEEE 754R 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; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + if (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]; + } + 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]); + } + + 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, + enum machine_mode mode) +{ + char string[256]; + decimal128 *d128; + d128 = (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 + represenation 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 ((decimal128 *) a->sig, &dn2); + decimal128ToNumber ((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, enum 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) +{ + decimal128 *d128 = (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 ((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 ((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 to an integer pair, HI+LOW. */ + +void +decimal_real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh, + 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 ((decimal128 *) r->sig, &dn); + + decNumberToIntegralValue (&dn2, &dn, &set); + decNumberZero (&dn3); + decNumberRescale (&dn, &dn2, &dn3, &set); + + /* Conver to REAL_VALUE_TYPE and call appropriate conversion + function. */ + decNumberToString (&dn, string); + real_from_string (&to, string); + real_to_integer2 (plow, phigh, &to); +} + +/* Perform the decimal floating point operation described by COODE. + For a unary operation, leave OP1 NULL. This function returns true + if the result may be inexact due to loss of precision. */ + +bool +decimal_real_arithmetic (REAL_VALUE_TYPE *r, int icode, + const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) +{ + enum tree_code code = icode; + REAL_VALUE_TYPE a1; + REAL_VALUE_TYPE b1; + + /* If either op is not a decimal, create a temporary decimal + versions. */ + if (!op0->decimal) + { + decimal_from_binary (&a1, op0); + op0 = &a1; + } + if (op1 && !op1->decimal) + { + decimal_from_binary (&b1, op1); + op1 = &b1; + } + + switch (code) + { + case PLUS_EXPR: + (void) decimal_do_add (r, op0, op1, 0); + break; + + case MINUS_EXPR: + (void) decimal_do_add (r, op0, op1, 1); + break; + + case MULT_EXPR: + (void) decimal_do_multiply (r, op0, op1); + break; + + case RDIV_EXPR: + (void) decimal_do_divide (r, op0, op1); + break; + + case MIN_EXPR: + if (op1->cl == rvc_nan) + *r = *op1; + else if (real_compare (UNLT_EXPR, op0, op1)) + *r = *op0; + else + *r = *op1; + break; + + case MAX_EXPR: + if (op1->cl == rvc_nan) + *r = *op1; + else if (real_compare (LT_EXPR, op0, op1)) + *r = *op1; + else + *r = *op0; + break; + + case NEGATE_EXPR: + { + decimal128 *d128; + *r = *op0; + d128 = (decimal128 *) r->sig; + /* Flip high bit. */ + d128->bytes[0] ^= 1 << 7; + /* Keep sign field in sync. */ + r->sign ^= 1; + } + break; + + case ABS_EXPR: + { + decimal128 *d128; + *r = *op0; + d128 = (decimal128 *) r->sig; + /* Clear high bit. */ + d128->bytes[0] &= 0x7f; + /* Keep sign field in sync. */ + r->sign = 0; + } + break; + + case FIX_TRUNC_EXPR: + decimal_do_fix_trunc (r, op0); + break; + + default: + gcc_unreachable (); + } + + /* FIXME: Indicate all operations as inexact for now due to unknown + working precision. */ + return true; +} + +/* 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, enum machine_mode mode) +{ + char *max; + + switch (mode) + { + case SDmode: + max = (char *) "9.999999E96"; + break; + case DDmode: + max = (char *) "9.999999999999999E384"; + break; + case TDmode: + max = (char *) "9.999999999999999999999999999999999E6144"; + break; + default: + gcc_unreachable (); + } + + decimal_real_from_string (r, max); + if (sign) + r->sig[0] |= 0x80000000; +} |