Search
lxdream.org :: lxdream/src/xlat/disasm/floatformat.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/disasm/floatformat.c
changeset 1265:7c6c5d26fd2e
author nkeynes
date Fri May 29 18:47:05 2015 +1000 (8 years ago)
permissions -rw-r--r--
last change Fix test case
file annotate diff log raw
nkeynes@1265
     1
/* IEEE floating point support routines, for GDB, the GNU Debugger.
nkeynes@1265
     2
   Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006, 2010
nkeynes@1265
     3
   Free Software Foundation, Inc.
nkeynes@1265
     4
nkeynes@1265
     5
This file is part of GDB.
nkeynes@1265
     6
nkeynes@1265
     7
This program is free software; you can redistribute it and/or modify
nkeynes@1265
     8
it under the terms of the GNU General Public License as published by
nkeynes@1265
     9
the Free Software Foundation; either version 2 of the License, or
nkeynes@1265
    10
(at your option) any later version.
nkeynes@1265
    11
nkeynes@1265
    12
This program is distributed in the hope that it will be useful,
nkeynes@1265
    13
but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1265
    14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1265
    15
GNU General Public License for more details.
nkeynes@1265
    16
nkeynes@1265
    17
You should have received a copy of the GNU General Public License
nkeynes@1265
    18
along with this program; if not, write to the Free Software
nkeynes@1265
    19
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
nkeynes@1265
    20
nkeynes@1265
    21
#ifdef HAVE_CONFIG_H
nkeynes@1265
    22
#include "config.h"
nkeynes@1265
    23
#endif
nkeynes@1265
    24
nkeynes@1265
    25
#include <math.h>
nkeynes@1265
    26
nkeynes@1265
    27
#ifdef HAVE_STRING_H
nkeynes@1265
    28
#include <string.h>
nkeynes@1265
    29
#endif
nkeynes@1265
    30
nkeynes@1265
    31
/* On some platforms, <float.h> provides DBL_QNAN.  */
nkeynes@1265
    32
#ifdef STDC_HEADERS
nkeynes@1265
    33
#include <float.h>
nkeynes@1265
    34
#endif
nkeynes@1265
    35
nkeynes@1265
    36
#include "ansidecl.h"
nkeynes@1265
    37
#include "floatformat.h"
nkeynes@1265
    38
nkeynes@1265
    39
#ifndef INFINITY
nkeynes@1265
    40
#ifdef HUGE_VAL
nkeynes@1265
    41
#define INFINITY HUGE_VAL
nkeynes@1265
    42
#else
nkeynes@1265
    43
#define INFINITY (1.0 / 0.0)
nkeynes@1265
    44
#endif
nkeynes@1265
    45
#endif
nkeynes@1265
    46
nkeynes@1265
    47
#ifndef NAN
nkeynes@1265
    48
#ifdef DBL_QNAN
nkeynes@1265
    49
#define NAN DBL_QNAN
nkeynes@1265
    50
#else
nkeynes@1265
    51
#define NAN (0.0 / 0.0)
nkeynes@1265
    52
#endif
nkeynes@1265
    53
#endif
nkeynes@1265
    54
nkeynes@1265
    55
static int mant_bits_set (const struct floatformat *, const unsigned char *);
nkeynes@1265
    56
static unsigned long get_field (const unsigned char *,
nkeynes@1265
    57
                                enum floatformat_byteorders,
nkeynes@1265
    58
                                unsigned int,
nkeynes@1265
    59
                                unsigned int,
nkeynes@1265
    60
                                unsigned int);
nkeynes@1265
    61
static int floatformat_always_valid (const struct floatformat *fmt,
nkeynes@1265
    62
                                     const void *from);
nkeynes@1265
    63
nkeynes@1265
    64
static int
nkeynes@1265
    65
floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
nkeynes@1265
    66
                          const void *from ATTRIBUTE_UNUSED)
nkeynes@1265
    67
{
nkeynes@1265
    68
  return 1;
nkeynes@1265
    69
}
nkeynes@1265
    70
nkeynes@1265
    71
/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
nkeynes@1265
    72
   going to bother with trying to muck around with whether it is defined in
nkeynes@1265
    73
   a system header, what we do if not, etc.  */
nkeynes@1265
    74
#define FLOATFORMAT_CHAR_BIT 8
nkeynes@1265
    75
nkeynes@1265
    76
/* floatformats for IEEE half, single and double, big and little endian.  */
nkeynes@1265
    77
const struct floatformat floatformat_ieee_half_big =
nkeynes@1265
    78
{
nkeynes@1265
    79
  floatformat_big, 16, 0, 1, 5, 15, 31, 6, 10,
nkeynes@1265
    80
  floatformat_intbit_no,
nkeynes@1265
    81
  "floatformat_ieee_half_big",
nkeynes@1265
    82
  floatformat_always_valid,
nkeynes@1265
    83
  NULL
nkeynes@1265
    84
};
nkeynes@1265
    85
const struct floatformat floatformat_ieee_half_little =
nkeynes@1265
    86
{
nkeynes@1265
    87
  floatformat_little, 16, 0, 1, 5, 15, 31, 6, 10,
nkeynes@1265
    88
  floatformat_intbit_no,
nkeynes@1265
    89
  "floatformat_ieee_half_little",
nkeynes@1265
    90
  floatformat_always_valid,
nkeynes@1265
    91
  NULL
nkeynes@1265
    92
};
nkeynes@1265
    93
const struct floatformat floatformat_ieee_single_big =
nkeynes@1265
    94
{
nkeynes@1265
    95
  floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
nkeynes@1265
    96
  floatformat_intbit_no,
nkeynes@1265
    97
  "floatformat_ieee_single_big",
nkeynes@1265
    98
  floatformat_always_valid,
nkeynes@1265
    99
  NULL
nkeynes@1265
   100
};
nkeynes@1265
   101
const struct floatformat floatformat_ieee_single_little =
nkeynes@1265
   102
{
nkeynes@1265
   103
  floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
nkeynes@1265
   104
  floatformat_intbit_no,
nkeynes@1265
   105
  "floatformat_ieee_single_little",
nkeynes@1265
   106
  floatformat_always_valid,
nkeynes@1265
   107
  NULL
nkeynes@1265
   108
};
nkeynes@1265
   109
const struct floatformat floatformat_ieee_double_big =
nkeynes@1265
   110
{
nkeynes@1265
   111
  floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
nkeynes@1265
   112
  floatformat_intbit_no,
nkeynes@1265
   113
  "floatformat_ieee_double_big",
nkeynes@1265
   114
  floatformat_always_valid,
nkeynes@1265
   115
  NULL
nkeynes@1265
   116
};
nkeynes@1265
   117
const struct floatformat floatformat_ieee_double_little =
nkeynes@1265
   118
{
nkeynes@1265
   119
  floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
nkeynes@1265
   120
  floatformat_intbit_no,
nkeynes@1265
   121
  "floatformat_ieee_double_little",
nkeynes@1265
   122
  floatformat_always_valid,
nkeynes@1265
   123
  NULL
nkeynes@1265
   124
};
nkeynes@1265
   125
nkeynes@1265
   126
/* floatformat for IEEE double, little endian byte order, with big endian word
nkeynes@1265
   127
   ordering, as on the ARM.  */
nkeynes@1265
   128
nkeynes@1265
   129
const struct floatformat floatformat_ieee_double_littlebyte_bigword =
nkeynes@1265
   130
{
nkeynes@1265
   131
  floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
nkeynes@1265
   132
  floatformat_intbit_no,
nkeynes@1265
   133
  "floatformat_ieee_double_littlebyte_bigword",
nkeynes@1265
   134
  floatformat_always_valid,
nkeynes@1265
   135
  NULL
nkeynes@1265
   136
};
nkeynes@1265
   137
nkeynes@1265
   138
/* floatformat for VAX.  Not quite IEEE, but close enough.  */
nkeynes@1265
   139
nkeynes@1265
   140
const struct floatformat floatformat_vax_f =
nkeynes@1265
   141
{
nkeynes@1265
   142
  floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23,
nkeynes@1265
   143
  floatformat_intbit_no,
nkeynes@1265
   144
  "floatformat_vax_f",
nkeynes@1265
   145
  floatformat_always_valid,
nkeynes@1265
   146
  NULL
nkeynes@1265
   147
};
nkeynes@1265
   148
const struct floatformat floatformat_vax_d =
nkeynes@1265
   149
{
nkeynes@1265
   150
  floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55,
nkeynes@1265
   151
  floatformat_intbit_no,
nkeynes@1265
   152
  "floatformat_vax_d",
nkeynes@1265
   153
  floatformat_always_valid,
nkeynes@1265
   154
  NULL
nkeynes@1265
   155
};
nkeynes@1265
   156
const struct floatformat floatformat_vax_g =
nkeynes@1265
   157
{
nkeynes@1265
   158
  floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52,
nkeynes@1265
   159
  floatformat_intbit_no,
nkeynes@1265
   160
  "floatformat_vax_g",
nkeynes@1265
   161
  floatformat_always_valid,
nkeynes@1265
   162
  NULL
nkeynes@1265
   163
};
nkeynes@1265
   164
nkeynes@1265
   165
static int floatformat_i387_ext_is_valid (const struct floatformat *fmt,
nkeynes@1265
   166
					  const void *from);
nkeynes@1265
   167
nkeynes@1265
   168
static int
nkeynes@1265
   169
floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from)
nkeynes@1265
   170
{
nkeynes@1265
   171
  /* In the i387 double-extended format, if the exponent is all ones,
nkeynes@1265
   172
     then the integer bit must be set.  If the exponent is neither 0
nkeynes@1265
   173
     nor ~0, the intbit must also be set.  Only if the exponent is
nkeynes@1265
   174
     zero can it be zero, and then it must be zero.  */
nkeynes@1265
   175
  unsigned long exponent, int_bit;
nkeynes@1265
   176
  const unsigned char *ufrom = (const unsigned char *) from;
nkeynes@1265
   177
nkeynes@1265
   178
  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
nkeynes@1265
   179
			fmt->exp_start, fmt->exp_len);
nkeynes@1265
   180
  int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
nkeynes@1265
   181
		       fmt->man_start, 1);
nkeynes@1265
   182
nkeynes@1265
   183
  if ((exponent == 0) != (int_bit == 0))
nkeynes@1265
   184
    return 0;
nkeynes@1265
   185
  else
nkeynes@1265
   186
    return 1;
nkeynes@1265
   187
}
nkeynes@1265
   188
nkeynes@1265
   189
const struct floatformat floatformat_i387_ext =
nkeynes@1265
   190
{
nkeynes@1265
   191
  floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
nkeynes@1265
   192
  floatformat_intbit_yes,
nkeynes@1265
   193
  "floatformat_i387_ext",
nkeynes@1265
   194
  floatformat_i387_ext_is_valid,
nkeynes@1265
   195
  NULL
nkeynes@1265
   196
};
nkeynes@1265
   197
const struct floatformat floatformat_m68881_ext =
nkeynes@1265
   198
{
nkeynes@1265
   199
  /* Note that the bits from 16 to 31 are unused.  */
nkeynes@1265
   200
  floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
nkeynes@1265
   201
  floatformat_intbit_yes,
nkeynes@1265
   202
  "floatformat_m68881_ext",
nkeynes@1265
   203
  floatformat_always_valid,
nkeynes@1265
   204
  NULL
nkeynes@1265
   205
};
nkeynes@1265
   206
const struct floatformat floatformat_i960_ext =
nkeynes@1265
   207
{
nkeynes@1265
   208
  /* Note that the bits from 0 to 15 are unused.  */
nkeynes@1265
   209
  floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
nkeynes@1265
   210
  floatformat_intbit_yes,
nkeynes@1265
   211
  "floatformat_i960_ext",
nkeynes@1265
   212
  floatformat_always_valid,
nkeynes@1265
   213
  NULL
nkeynes@1265
   214
};
nkeynes@1265
   215
const struct floatformat floatformat_m88110_ext =
nkeynes@1265
   216
{
nkeynes@1265
   217
  floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
nkeynes@1265
   218
  floatformat_intbit_yes,
nkeynes@1265
   219
  "floatformat_m88110_ext",
nkeynes@1265
   220
  floatformat_always_valid,
nkeynes@1265
   221
  NULL
nkeynes@1265
   222
};
nkeynes@1265
   223
const struct floatformat floatformat_m88110_harris_ext =
nkeynes@1265
   224
{
nkeynes@1265
   225
  /* Harris uses raw format 128 bytes long, but the number is just an ieee
nkeynes@1265
   226
     double, and the last 64 bits are wasted. */
nkeynes@1265
   227
  floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
nkeynes@1265
   228
  floatformat_intbit_no,
nkeynes@1265
   229
  "floatformat_m88110_ext_harris",
nkeynes@1265
   230
  floatformat_always_valid,
nkeynes@1265
   231
  NULL
nkeynes@1265
   232
};
nkeynes@1265
   233
const struct floatformat floatformat_arm_ext_big =
nkeynes@1265
   234
{
nkeynes@1265
   235
  /* Bits 1 to 16 are unused.  */
nkeynes@1265
   236
  floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
nkeynes@1265
   237
  floatformat_intbit_yes,
nkeynes@1265
   238
  "floatformat_arm_ext_big",
nkeynes@1265
   239
  floatformat_always_valid,
nkeynes@1265
   240
  NULL
nkeynes@1265
   241
};
nkeynes@1265
   242
const struct floatformat floatformat_arm_ext_littlebyte_bigword =
nkeynes@1265
   243
{
nkeynes@1265
   244
  /* Bits 1 to 16 are unused.  */
nkeynes@1265
   245
  floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
nkeynes@1265
   246
  floatformat_intbit_yes,
nkeynes@1265
   247
  "floatformat_arm_ext_littlebyte_bigword",
nkeynes@1265
   248
  floatformat_always_valid,
nkeynes@1265
   249
  NULL
nkeynes@1265
   250
};
nkeynes@1265
   251
const struct floatformat floatformat_ia64_spill_big =
nkeynes@1265
   252
{
nkeynes@1265
   253
  floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
nkeynes@1265
   254
  floatformat_intbit_yes,
nkeynes@1265
   255
  "floatformat_ia64_spill_big",
nkeynes@1265
   256
  floatformat_always_valid,
nkeynes@1265
   257
  NULL
nkeynes@1265
   258
};
nkeynes@1265
   259
const struct floatformat floatformat_ia64_spill_little =
nkeynes@1265
   260
{
nkeynes@1265
   261
  floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
nkeynes@1265
   262
  floatformat_intbit_yes,
nkeynes@1265
   263
  "floatformat_ia64_spill_little",
nkeynes@1265
   264
  floatformat_always_valid,
nkeynes@1265
   265
  NULL
nkeynes@1265
   266
};
nkeynes@1265
   267
const struct floatformat floatformat_ia64_quad_big =
nkeynes@1265
   268
{
nkeynes@1265
   269
  floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
nkeynes@1265
   270
  floatformat_intbit_no,
nkeynes@1265
   271
  "floatformat_ia64_quad_big",
nkeynes@1265
   272
  floatformat_always_valid,
nkeynes@1265
   273
  NULL
nkeynes@1265
   274
};
nkeynes@1265
   275
const struct floatformat floatformat_ia64_quad_little =
nkeynes@1265
   276
{
nkeynes@1265
   277
  floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
nkeynes@1265
   278
  floatformat_intbit_no,
nkeynes@1265
   279
  "floatformat_ia64_quad_little",
nkeynes@1265
   280
  floatformat_always_valid,
nkeynes@1265
   281
  NULL
nkeynes@1265
   282
};
nkeynes@1265
   283
nkeynes@1265
   284
static int
nkeynes@1265
   285
floatformat_ibm_long_double_is_valid (const struct floatformat *fmt,
nkeynes@1265
   286
				      const void *from)
nkeynes@1265
   287
{
nkeynes@1265
   288
  const unsigned char *ufrom = (const unsigned char *) from;
nkeynes@1265
   289
  const struct floatformat *hfmt = fmt->split_half;
nkeynes@1265
   290
  long top_exp, bot_exp;
nkeynes@1265
   291
  int top_nan = 0;
nkeynes@1265
   292
nkeynes@1265
   293
  top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
nkeynes@1265
   294
		       hfmt->exp_start, hfmt->exp_len);
nkeynes@1265
   295
  bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
nkeynes@1265
   296
		       hfmt->exp_start, hfmt->exp_len);
nkeynes@1265
   297
nkeynes@1265
   298
  if ((unsigned long) top_exp == hfmt->exp_nan)
nkeynes@1265
   299
    top_nan = mant_bits_set (hfmt, ufrom);
nkeynes@1265
   300
nkeynes@1265
   301
  /* A NaN is valid with any low part.  */
nkeynes@1265
   302
  if (top_nan)
nkeynes@1265
   303
    return 1;
nkeynes@1265
   304
nkeynes@1265
   305
  /* An infinity, zero or denormal requires low part 0 (positive or
nkeynes@1265
   306
     negative).  */
nkeynes@1265
   307
  if ((unsigned long) top_exp == hfmt->exp_nan || top_exp == 0)
nkeynes@1265
   308
    {
nkeynes@1265
   309
      if (bot_exp != 0)
nkeynes@1265
   310
	return 0;
nkeynes@1265
   311
nkeynes@1265
   312
      return !mant_bits_set (hfmt, ufrom + 8);
nkeynes@1265
   313
    }
nkeynes@1265
   314
nkeynes@1265
   315
  /* The top part is now a finite normal value.  The long double value
nkeynes@1265
   316
     is the sum of the two parts, and the top part must equal the
nkeynes@1265
   317
     result of rounding the long double value to nearest double.  Thus
nkeynes@1265
   318
     the bottom part must be <= 0.5ulp of the top part in absolute
nkeynes@1265
   319
     value, and if it is < 0.5ulp then the long double is definitely
nkeynes@1265
   320
     valid.  */
nkeynes@1265
   321
  if (bot_exp < top_exp - 53)
nkeynes@1265
   322
    return 1;
nkeynes@1265
   323
  if (bot_exp > top_exp - 53 && bot_exp != 0)
nkeynes@1265
   324
    return 0;
nkeynes@1265
   325
  if (bot_exp == 0)
nkeynes@1265
   326
    {
nkeynes@1265
   327
      /* The bottom part is 0 or denormal.  Determine which, and if
nkeynes@1265
   328
	 denormal the first two set bits.  */
nkeynes@1265
   329
      int first_bit = -1, second_bit = -1, cur_bit;
nkeynes@1265
   330
      for (cur_bit = 0; (unsigned int) cur_bit < hfmt->man_len; cur_bit++)
nkeynes@1265
   331
	if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize,
nkeynes@1265
   332
		       hfmt->man_start + cur_bit, 1))
nkeynes@1265
   333
	  {
nkeynes@1265
   334
	    if (first_bit == -1)
nkeynes@1265
   335
	      first_bit = cur_bit;
nkeynes@1265
   336
	    else
nkeynes@1265
   337
	      {
nkeynes@1265
   338
		second_bit = cur_bit;
nkeynes@1265
   339
		break;
nkeynes@1265
   340
	      }
nkeynes@1265
   341
	  }
nkeynes@1265
   342
      /* Bottom part 0 is OK.  */
nkeynes@1265
   343
      if (first_bit == -1)
nkeynes@1265
   344
	return 1;
nkeynes@1265
   345
      /* The real exponent of the bottom part is -first_bit.  */
nkeynes@1265
   346
      if (-first_bit < top_exp - 53)
nkeynes@1265
   347
	return 1;
nkeynes@1265
   348
      if (-first_bit > top_exp - 53)
nkeynes@1265
   349
	return 0;
nkeynes@1265
   350
      /* The bottom part is at least 0.5ulp of the top part.  For this
nkeynes@1265
   351
	 to be OK, the bottom part must be exactly 0.5ulp (i.e. no
nkeynes@1265
   352
	 more bits set) and the top part must have last bit 0.  */
nkeynes@1265
   353
      if (second_bit != -1)
nkeynes@1265
   354
	return 0;
nkeynes@1265
   355
      return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
nkeynes@1265
   356
			 hfmt->man_start + hfmt->man_len - 1, 1);
nkeynes@1265
   357
    }
nkeynes@1265
   358
  else
nkeynes@1265
   359
    {
nkeynes@1265
   360
      /* The bottom part is at least 0.5ulp of the top part.  For this
nkeynes@1265
   361
	 to be OK, it must be exactly 0.5ulp (i.e. no explicit bits
nkeynes@1265
   362
	 set) and the top part must have last bit 0.  */
nkeynes@1265
   363
      if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize,
nkeynes@1265
   364
		     hfmt->man_start + hfmt->man_len - 1, 1))
nkeynes@1265
   365
	return 0;
nkeynes@1265
   366
      return !mant_bits_set (hfmt, ufrom + 8);
nkeynes@1265
   367
    }
nkeynes@1265
   368
}
nkeynes@1265
   369
nkeynes@1265
   370
const struct floatformat floatformat_ibm_long_double =
nkeynes@1265
   371
{
nkeynes@1265
   372
  floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
nkeynes@1265
   373
  floatformat_intbit_no,
nkeynes@1265
   374
  "floatformat_ibm_long_double",
nkeynes@1265
   375
  floatformat_ibm_long_double_is_valid,
nkeynes@1265
   376
  &floatformat_ieee_double_big
nkeynes@1265
   377
};
nkeynes@1265
   378

nkeynes@1265
   379
nkeynes@1265
   380
#ifndef min
nkeynes@1265
   381
#define min(a, b) ((a) < (b) ? (a) : (b))
nkeynes@1265
   382
#endif
nkeynes@1265
   383
nkeynes@1265
   384
/* Return 1 if any bits are explicitly set in the mantissa of UFROM,
nkeynes@1265
   385
   format FMT, 0 otherwise.  */
nkeynes@1265
   386
static int
nkeynes@1265
   387
mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom)
nkeynes@1265
   388
{
nkeynes@1265
   389
  unsigned int mant_bits, mant_off;
nkeynes@1265
   390
  int mant_bits_left;
nkeynes@1265
   391
nkeynes@1265
   392
  mant_off = fmt->man_start;
nkeynes@1265
   393
  mant_bits_left = fmt->man_len;
nkeynes@1265
   394
  while (mant_bits_left > 0)
nkeynes@1265
   395
    {
nkeynes@1265
   396
      mant_bits = min (mant_bits_left, 32);
nkeynes@1265
   397
nkeynes@1265
   398
      if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
nkeynes@1265
   399
		     mant_off, mant_bits) != 0)
nkeynes@1265
   400
	return 1;
nkeynes@1265
   401
nkeynes@1265
   402
      mant_off += mant_bits;
nkeynes@1265
   403
      mant_bits_left -= mant_bits;
nkeynes@1265
   404
    }
nkeynes@1265
   405
  return 0;
nkeynes@1265
   406
}
nkeynes@1265
   407
nkeynes@1265
   408
/* Extract a field which starts at START and is LEN bits long.  DATA and
nkeynes@1265
   409
   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
nkeynes@1265
   410
static unsigned long
nkeynes@1265
   411
get_field (const unsigned char *data, enum floatformat_byteorders order,
nkeynes@1265
   412
           unsigned int total_len, unsigned int start, unsigned int len)
nkeynes@1265
   413
{
nkeynes@1265
   414
  unsigned long result = 0;
nkeynes@1265
   415
  unsigned int cur_byte;
nkeynes@1265
   416
  int lo_bit, hi_bit, cur_bitshift = 0;
nkeynes@1265
   417
  int nextbyte = (order == floatformat_little) ? 1 : -1;
nkeynes@1265
   418
nkeynes@1265
   419
  /* Start is in big-endian bit order!  Fix that first.  */
nkeynes@1265
   420
  start = total_len - (start + len);
nkeynes@1265
   421
nkeynes@1265
   422
  /* Start at the least significant part of the field.  */
nkeynes@1265
   423
  if (order == floatformat_little)
nkeynes@1265
   424
    cur_byte = start / FLOATFORMAT_CHAR_BIT;
nkeynes@1265
   425
  else
nkeynes@1265
   426
    cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
nkeynes@1265
   427
nkeynes@1265
   428
  lo_bit = start % FLOATFORMAT_CHAR_BIT;
nkeynes@1265
   429
  hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
nkeynes@1265
   430
  
nkeynes@1265
   431
  do
nkeynes@1265
   432
    {
nkeynes@1265
   433
      unsigned int shifted = *(data + cur_byte) >> lo_bit;
nkeynes@1265
   434
      unsigned int bits = hi_bit - lo_bit;
nkeynes@1265
   435
      unsigned int mask = (1 << bits) - 1;
nkeynes@1265
   436
      result |= (shifted & mask) << cur_bitshift;
nkeynes@1265
   437
      len -= bits;
nkeynes@1265
   438
      cur_bitshift += bits;
nkeynes@1265
   439
      cur_byte += nextbyte;
nkeynes@1265
   440
      lo_bit = 0;
nkeynes@1265
   441
      hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
nkeynes@1265
   442
    }
nkeynes@1265
   443
  while (len != 0);
nkeynes@1265
   444
nkeynes@1265
   445
  return result;
nkeynes@1265
   446
}
nkeynes@1265
   447
  
nkeynes@1265
   448
/* Convert from FMT to a double.
nkeynes@1265
   449
   FROM is the address of the extended float.
nkeynes@1265
   450
   Store the double in *TO.  */
nkeynes@1265
   451
nkeynes@1265
   452
void
nkeynes@1265
   453
floatformat_to_double (const struct floatformat *fmt,
nkeynes@1265
   454
                       const void *from, double *to)
nkeynes@1265
   455
{
nkeynes@1265
   456
  const unsigned char *ufrom = (const unsigned char *) from;
nkeynes@1265
   457
  double dto;
nkeynes@1265
   458
  long exponent;
nkeynes@1265
   459
  unsigned long mant;
nkeynes@1265
   460
  unsigned int mant_bits, mant_off;
nkeynes@1265
   461
  int mant_bits_left;
nkeynes@1265
   462
  int special_exponent;		/* It's a NaN, denorm or zero */
nkeynes@1265
   463
nkeynes@1265
   464
  /* Split values are not handled specially, since the top half has
nkeynes@1265
   465
     the correctly rounded double value (in the only supported case of
nkeynes@1265
   466
     split values).  */
nkeynes@1265
   467
nkeynes@1265
   468
  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
nkeynes@1265
   469
			fmt->exp_start, fmt->exp_len);
nkeynes@1265
   470
nkeynes@1265
   471
  /* If the exponent indicates a NaN, we don't have information to
nkeynes@1265
   472
     decide what to do.  So we handle it like IEEE, except that we
nkeynes@1265
   473
     don't try to preserve the type of NaN.  FIXME.  */
nkeynes@1265
   474
  if ((unsigned long) exponent == fmt->exp_nan)
nkeynes@1265
   475
    {
nkeynes@1265
   476
      int nan = mant_bits_set (fmt, ufrom);
nkeynes@1265
   477
nkeynes@1265
   478
      /* On certain systems (such as GNU/Linux), the use of the
nkeynes@1265
   479
	 INFINITY macro below may generate a warning that can not be
nkeynes@1265
   480
	 silenced due to a bug in GCC (PR preprocessor/11931).  The
nkeynes@1265
   481
	 preprocessor fails to recognise the __extension__ keyword in
nkeynes@1265
   482
	 conjunction with the GNU/C99 extension for hexadecimal
nkeynes@1265
   483
	 floating point constants and will issue a warning when
nkeynes@1265
   484
	 compiling with -pedantic.  */
nkeynes@1265
   485
      if (nan)
nkeynes@1265
   486
	dto = NAN;
nkeynes@1265
   487
      else
nkeynes@1265
   488
	dto = INFINITY;
nkeynes@1265
   489
nkeynes@1265
   490
      if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
nkeynes@1265
   491
	dto = -dto;
nkeynes@1265
   492
nkeynes@1265
   493
      *to = dto;
nkeynes@1265
   494
nkeynes@1265
   495
      return;
nkeynes@1265
   496
    }
nkeynes@1265
   497
nkeynes@1265
   498
  mant_bits_left = fmt->man_len;
nkeynes@1265
   499
  mant_off = fmt->man_start;
nkeynes@1265
   500
  dto = 0.0;
nkeynes@1265
   501
nkeynes@1265
   502
  special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
nkeynes@1265
   503
nkeynes@1265
   504
  /* Don't bias zero's, denorms or NaNs.  */
nkeynes@1265
   505
  if (!special_exponent)
nkeynes@1265
   506
    exponent -= fmt->exp_bias;
nkeynes@1265
   507
nkeynes@1265
   508
  /* Build the result algebraically.  Might go infinite, underflow, etc;
nkeynes@1265
   509
     who cares. */
nkeynes@1265
   510
nkeynes@1265
   511
  /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
nkeynes@1265
   512
     increment the exponent by one to account for the integer bit.  */
nkeynes@1265
   513
nkeynes@1265
   514
  if (!special_exponent)
nkeynes@1265
   515
    {
nkeynes@1265
   516
      if (fmt->intbit == floatformat_intbit_no)
nkeynes@1265
   517
	dto = ldexp (1.0, exponent);
nkeynes@1265
   518
      else
nkeynes@1265
   519
	exponent++;
nkeynes@1265
   520
    }
nkeynes@1265
   521
nkeynes@1265
   522
  while (mant_bits_left > 0)
nkeynes@1265
   523
    {
nkeynes@1265
   524
      mant_bits = min (mant_bits_left, 32);
nkeynes@1265
   525
nkeynes@1265
   526
      mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
nkeynes@1265
   527
			 mant_off, mant_bits);
nkeynes@1265
   528
nkeynes@1265
   529
      /* Handle denormalized numbers.  FIXME: What should we do for
nkeynes@1265
   530
	 non-IEEE formats?  */
nkeynes@1265
   531
      if (special_exponent && exponent == 0 && mant != 0)
nkeynes@1265
   532
	dto += ldexp ((double)mant,
nkeynes@1265
   533
		      (- fmt->exp_bias
nkeynes@1265
   534
		       - mant_bits
nkeynes@1265
   535
		       - (mant_off - fmt->man_start)
nkeynes@1265
   536
		       + 1));
nkeynes@1265
   537
      else
nkeynes@1265
   538
	dto += ldexp ((double)mant, exponent - mant_bits);
nkeynes@1265
   539
      if (exponent != 0)
nkeynes@1265
   540
	exponent -= mant_bits;
nkeynes@1265
   541
      mant_off += mant_bits;
nkeynes@1265
   542
      mant_bits_left -= mant_bits;
nkeynes@1265
   543
    }
nkeynes@1265
   544
nkeynes@1265
   545
  /* Negate it if negative.  */
nkeynes@1265
   546
  if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
nkeynes@1265
   547
    dto = -dto;
nkeynes@1265
   548
  *to = dto;
nkeynes@1265
   549
}
nkeynes@1265
   550

nkeynes@1265
   551
static void put_field (unsigned char *, enum floatformat_byteorders,
nkeynes@1265
   552
                       unsigned int,
nkeynes@1265
   553
                       unsigned int,
nkeynes@1265
   554
                       unsigned int,
nkeynes@1265
   555
                       unsigned long);
nkeynes@1265
   556
nkeynes@1265
   557
/* Set a field which starts at START and is LEN bits long.  DATA and
nkeynes@1265
   558
   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
nkeynes@1265
   559
static void
nkeynes@1265
   560
put_field (unsigned char *data, enum floatformat_byteorders order,
nkeynes@1265
   561
           unsigned int total_len, unsigned int start, unsigned int len,
nkeynes@1265
   562
           unsigned long stuff_to_put)
nkeynes@1265
   563
{
nkeynes@1265
   564
  unsigned int cur_byte;
nkeynes@1265
   565
  int lo_bit, hi_bit;
nkeynes@1265
   566
  int nextbyte = (order == floatformat_little) ? 1 : -1;
nkeynes@1265
   567
nkeynes@1265
   568
  /* Start is in big-endian bit order!  Fix that first.  */
nkeynes@1265
   569
  start = total_len - (start + len);
nkeynes@1265
   570
nkeynes@1265
   571
  /* Start at the least significant part of the field.  */
nkeynes@1265
   572
  if (order == floatformat_little)
nkeynes@1265
   573
    cur_byte = start / FLOATFORMAT_CHAR_BIT;
nkeynes@1265
   574
  else
nkeynes@1265
   575
    cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
nkeynes@1265
   576
nkeynes@1265
   577
  lo_bit = start % FLOATFORMAT_CHAR_BIT;
nkeynes@1265
   578
  hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
nkeynes@1265
   579
  
nkeynes@1265
   580
  do
nkeynes@1265
   581
    {
nkeynes@1265
   582
      unsigned char *byte_ptr = data + cur_byte;
nkeynes@1265
   583
      unsigned int bits = hi_bit - lo_bit;
nkeynes@1265
   584
      unsigned int mask = ((1 << bits) - 1) << lo_bit;
nkeynes@1265
   585
      *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask);
nkeynes@1265
   586
      stuff_to_put >>= bits;
nkeynes@1265
   587
      len -= bits;
nkeynes@1265
   588
      cur_byte += nextbyte;
nkeynes@1265
   589
      lo_bit = 0;
nkeynes@1265
   590
      hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
nkeynes@1265
   591
    }
nkeynes@1265
   592
  while (len != 0);
nkeynes@1265
   593
}
nkeynes@1265
   594
nkeynes@1265
   595
/* The converse: convert the double *FROM to an extended float
nkeynes@1265
   596
   and store where TO points.  Neither FROM nor TO have any alignment
nkeynes@1265
   597
   restrictions.  */
nkeynes@1265
   598
nkeynes@1265
   599
void
nkeynes@1265
   600
floatformat_from_double (const struct floatformat *fmt,
nkeynes@1265
   601
                         const double *from, void *to)
nkeynes@1265
   602
{
nkeynes@1265
   603
  double dfrom;
nkeynes@1265
   604
  int exponent;
nkeynes@1265
   605
  double mant;
nkeynes@1265
   606
  unsigned int mant_bits, mant_off;
nkeynes@1265
   607
  int mant_bits_left;
nkeynes@1265
   608
  unsigned char *uto = (unsigned char *) to;
nkeynes@1265
   609
nkeynes@1265
   610
  dfrom = *from;
nkeynes@1265
   611
  memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
nkeynes@1265
   612
nkeynes@1265
   613
  /* Split values are not handled specially, since a bottom half of
nkeynes@1265
   614
     zero is correct for any value representable as double (in the
nkeynes@1265
   615
     only supported case of split values).  */
nkeynes@1265
   616
nkeynes@1265
   617
  /* If negative, set the sign bit.  */
nkeynes@1265
   618
  if (dfrom < 0)
nkeynes@1265
   619
    {
nkeynes@1265
   620
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
nkeynes@1265
   621
      dfrom = -dfrom;
nkeynes@1265
   622
    }
nkeynes@1265
   623
nkeynes@1265
   624
  if (dfrom == 0)
nkeynes@1265
   625
    {
nkeynes@1265
   626
      /* 0.0.  */
nkeynes@1265
   627
      return;
nkeynes@1265
   628
    }
nkeynes@1265
   629
nkeynes@1265
   630
  if (dfrom != dfrom)
nkeynes@1265
   631
    {
nkeynes@1265
   632
      /* NaN.  */
nkeynes@1265
   633
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
nkeynes@1265
   634
		 fmt->exp_len, fmt->exp_nan);
nkeynes@1265
   635
      /* Be sure it's not infinity, but NaN value is irrelevant.  */
nkeynes@1265
   636
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
nkeynes@1265
   637
		 32, 1);
nkeynes@1265
   638
      return;
nkeynes@1265
   639
    }
nkeynes@1265
   640
nkeynes@1265
   641
  if (dfrom + dfrom == dfrom)
nkeynes@1265
   642
    {
nkeynes@1265
   643
      /* This can only happen for an infinite value (or zero, which we
nkeynes@1265
   644
	 already handled above).  */
nkeynes@1265
   645
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
nkeynes@1265
   646
		 fmt->exp_len, fmt->exp_nan);
nkeynes@1265
   647
      return;
nkeynes@1265
   648
    }
nkeynes@1265
   649
nkeynes@1265
   650
  mant = frexp (dfrom, &exponent);
nkeynes@1265
   651
  if (exponent + fmt->exp_bias - 1 > 0)
nkeynes@1265
   652
    put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
nkeynes@1265
   653
	       fmt->exp_len, exponent + fmt->exp_bias - 1);
nkeynes@1265
   654
  else
nkeynes@1265
   655
    {
nkeynes@1265
   656
      /* Handle a denormalized number.  FIXME: What should we do for
nkeynes@1265
   657
	 non-IEEE formats?  */
nkeynes@1265
   658
      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
nkeynes@1265
   659
		 fmt->exp_len, 0);
nkeynes@1265
   660
      mant = ldexp (mant, exponent + fmt->exp_bias - 1);
nkeynes@1265
   661
    }
nkeynes@1265
   662
nkeynes@1265
   663
  mant_bits_left = fmt->man_len;
nkeynes@1265
   664
  mant_off = fmt->man_start;
nkeynes@1265
   665
  while (mant_bits_left > 0)
nkeynes@1265
   666
    {
nkeynes@1265
   667
      unsigned long mant_long;
nkeynes@1265
   668
      mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
nkeynes@1265
   669
nkeynes@1265
   670
      mant *= 4294967296.0;
nkeynes@1265
   671
      mant_long = (unsigned long)mant;
nkeynes@1265
   672
      mant -= mant_long;
nkeynes@1265
   673
nkeynes@1265
   674
      /* If the integer bit is implicit, and we are not creating a
nkeynes@1265
   675
	 denormalized number, then we need to discard it.  */
nkeynes@1265
   676
      if ((unsigned int) mant_bits_left == fmt->man_len
nkeynes@1265
   677
	  && fmt->intbit == floatformat_intbit_no
nkeynes@1265
   678
	  && exponent + fmt->exp_bias - 1 > 0)
nkeynes@1265
   679
	{
nkeynes@1265
   680
	  mant_long &= 0x7fffffff;
nkeynes@1265
   681
	  mant_bits -= 1;
nkeynes@1265
   682
	}
nkeynes@1265
   683
      else if (mant_bits < 32)
nkeynes@1265
   684
	{
nkeynes@1265
   685
	  /* The bits we want are in the most significant MANT_BITS bits of
nkeynes@1265
   686
	     mant_long.  Move them to the least significant.  */
nkeynes@1265
   687
	  mant_long >>= 32 - mant_bits;
nkeynes@1265
   688
	}
nkeynes@1265
   689
nkeynes@1265
   690
      put_field (uto, fmt->byteorder, fmt->totalsize,
nkeynes@1265
   691
		 mant_off, mant_bits, mant_long);
nkeynes@1265
   692
      mant_off += mant_bits;
nkeynes@1265
   693
      mant_bits_left -= mant_bits;
nkeynes@1265
   694
    }
nkeynes@1265
   695
}
nkeynes@1265
   696
nkeynes@1265
   697
/* Return non-zero iff the data at FROM is a valid number in format FMT.  */
nkeynes@1265
   698
nkeynes@1265
   699
int
nkeynes@1265
   700
floatformat_is_valid (const struct floatformat *fmt, const void *from)
nkeynes@1265
   701
{
nkeynes@1265
   702
  return fmt->is_valid (fmt, from);
nkeynes@1265
   703
}
nkeynes@1265
   704
nkeynes@1265
   705
nkeynes@1265
   706
#ifdef IEEE_DEBUG
nkeynes@1265
   707
nkeynes@1265
   708
#include <stdio.h>
nkeynes@1265
   709
nkeynes@1265
   710
/* This is to be run on a host which uses IEEE floating point.  */
nkeynes@1265
   711
nkeynes@1265
   712
void
nkeynes@1265
   713
ieee_test (double n)
nkeynes@1265
   714
{
nkeynes@1265
   715
  double result;
nkeynes@1265
   716
nkeynes@1265
   717
  floatformat_to_double (&floatformat_ieee_double_little, &n, &result);
nkeynes@1265
   718
  if ((n != result && (! isnan (n) || ! isnan (result)))
nkeynes@1265
   719
      || (n < 0 && result >= 0)
nkeynes@1265
   720
      || (n >= 0 && result < 0))
nkeynes@1265
   721
    printf ("Differ(to): %.20g -> %.20g\n", n, result);
nkeynes@1265
   722
nkeynes@1265
   723
  floatformat_from_double (&floatformat_ieee_double_little, &n, &result);
nkeynes@1265
   724
  if ((n != result && (! isnan (n) || ! isnan (result)))
nkeynes@1265
   725
      || (n < 0 && result >= 0)
nkeynes@1265
   726
      || (n >= 0 && result < 0))
nkeynes@1265
   727
    printf ("Differ(from): %.20g -> %.20g\n", n, result);
nkeynes@1265
   728
nkeynes@1265
   729
#if 0
nkeynes@1265
   730
  {
nkeynes@1265
   731
    char exten[16];
nkeynes@1265
   732
nkeynes@1265
   733
    floatformat_from_double (&floatformat_m68881_ext, &n, exten);
nkeynes@1265
   734
    floatformat_to_double (&floatformat_m68881_ext, exten, &result);
nkeynes@1265
   735
    if (n != result)
nkeynes@1265
   736
      printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
nkeynes@1265
   737
  }
nkeynes@1265
   738
#endif
nkeynes@1265
   739
nkeynes@1265
   740
#if IEEE_DEBUG > 1
nkeynes@1265
   741
  /* This is to be run on a host which uses 68881 format.  */
nkeynes@1265
   742
  {
nkeynes@1265
   743
    long double ex = *(long double *)exten;
nkeynes@1265
   744
    if (ex != n)
nkeynes@1265
   745
      printf ("Differ(from vs. extended): %.20g\n", n);
nkeynes@1265
   746
  }
nkeynes@1265
   747
#endif
nkeynes@1265
   748
}
nkeynes@1265
   749
nkeynes@1265
   750
int
nkeynes@1265
   751
main (void)
nkeynes@1265
   752
{
nkeynes@1265
   753
  ieee_test (0.0);
nkeynes@1265
   754
  ieee_test (0.5);
nkeynes@1265
   755
  ieee_test (256.0);
nkeynes@1265
   756
  ieee_test (0.12345);
nkeynes@1265
   757
  ieee_test (234235.78907234);
nkeynes@1265
   758
  ieee_test (-512.0);
nkeynes@1265
   759
  ieee_test (-0.004321);
nkeynes@1265
   760
  ieee_test (1.2E-70);
nkeynes@1265
   761
  ieee_test (1.2E-316);
nkeynes@1265
   762
  ieee_test (4.9406564584124654E-324);
nkeynes@1265
   763
  ieee_test (- 4.9406564584124654E-324);
nkeynes@1265
   764
  ieee_test (- 0.0);
nkeynes@1265
   765
  ieee_test (- INFINITY);
nkeynes@1265
   766
  ieee_test (- NAN);
nkeynes@1265
   767
  ieee_test (INFINITY);
nkeynes@1265
   768
  ieee_test (NAN);
nkeynes@1265
   769
  return 0;
nkeynes@1265
   770
}
nkeynes@1265
   771
#endif
.