OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [dfp.c] - Diff between revs 154 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.