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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [dfp-bit.c] - Blame information for rev 827

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 38 julius
/* This is a software decimal floating point library.
2
   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
3
 
4
This file is part of GCC.
5
 
6
GCC is free software; you can redistribute it and/or modify it under
7
the terms of the GNU General Public License as published by the Free
8
Software Foundation; either version 2, or (at your option) any later
9
version.
10
 
11
In addition to the permissions in the GNU General Public License, the
12
Free Software Foundation gives you unlimited permission to link the
13
compiled version of this file into combinations with other programs,
14
and to distribute those combinations without any restriction coming
15
from the use of this file.  (The General Public License restrictions
16
do apply in other respects; for example, they cover modification of
17
the file, and distribution when not linked into a combine
18
executable.)
19
 
20
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
21
WARRANTY; without even the implied warranty of MERCHANTABILITY or
22
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23
for more details.
24
 
25
You should have received a copy of the GNU General Public License
26
along with GCC; see the file COPYING.  If not, write to the Free
27
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28
02110-1301, USA.  */
29
 
30
/* This implements IEEE 754R decimal floating point arithmetic, but
31
   does not provide a mechanism for setting the rounding mode, or for
32
   generating or handling exceptions.  Conversions between decimal
33
   floating point types and other types depend on C library functions.
34
 
35
   Contributed by Ben Elliston  <bje@au.ibm.com>.  */
36
 
37
/* The intended way to use this file is to make two copies, add `#define '
38
   to one copy, then compile both copies and add them to libgcc.a.  */
39
 
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <limits.h>
44
 
45
#include "config/dfp-bit.h"
46
 
47
/* Forward declarations.  */
48
#if WIDTH == 32 || WIDTH_TO == 32
49
void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
50
void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
51
#endif
52
#if WIDTH == 64 || WIDTH_TO == 64
53
void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
54
void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
55
#endif
56
#if WIDTH == 128 || WIDTH_TO == 128
57
void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
58
void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
59
#endif
60
 
61
/* A pointer to a unary decNumber operation.  */
62
typedef decNumber* (*dfp_unary_func)
63
     (decNumber *, decNumber *, decContext *);
64
 
65
/* A pointer to a binary decNumber operation.  */
66
typedef decNumber* (*dfp_binary_func)
67
     (decNumber *, decNumber *, decNumber *, decContext *);
68
 
69
extern unsigned long __dec_byte_swap (unsigned long);
70
 
71
/* Unary operations.  */
72
 
73
static inline DFP_C_TYPE
74
dfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg)
75
{
76
  DFP_C_TYPE result;
77
  decContext context;
78
  decNumber arg1, res;
79
  IEEE_TYPE a, encoded_result;
80
 
81
  HOST_TO_IEEE (arg, &a);
82
 
83
  decContextDefault (&context, CONTEXT_INIT);
84
  context.round = CONTEXT_ROUND;
85
 
86
  TO_INTERNAL (&a, &arg1);
87
 
88
  /* Perform the operation.  */
89
  op (&res, &arg1, &context);
90
 
91
  if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
92
    DFP_RAISE (0);
93
 
94
  TO_ENCODED (&encoded_result, &res, &context);
95
  IEEE_TO_HOST (encoded_result, &result);
96
  return result;
97
}
98
 
99
/* Binary operations.  */
100
 
101
static inline DFP_C_TYPE
102
dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
103
{
104
  DFP_C_TYPE result;
105
  decContext context;
106
  decNumber arg1, arg2, res;
107
  IEEE_TYPE a, b, encoded_result;
108
 
109
  HOST_TO_IEEE (arg_a, &a);
110
  HOST_TO_IEEE (arg_b, &b);
111
 
112
  decContextDefault (&context, CONTEXT_INIT);
113
  context.round = CONTEXT_ROUND;
114
 
115
  TO_INTERNAL (&a, &arg1);
116
  TO_INTERNAL (&b, &arg2);
117
 
118
  /* Perform the operation.  */
119
  op (&res, &arg1, &arg2, &context);
120
 
121
  if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
122
    DFP_RAISE (0);
123
 
124
  TO_ENCODED (&encoded_result, &res, &context);
125
  IEEE_TO_HOST (encoded_result, &result);
126
  return result;
127
}
128
 
129
/* Comparison operations.  */
130
 
131
static inline int
132
dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
133
{
134
  IEEE_TYPE a, b;
135
  decContext context;
136
  decNumber arg1, arg2, res;
137
  int result;
138
 
139
  HOST_TO_IEEE (arg_a, &a);
140
  HOST_TO_IEEE (arg_b, &b);
141
 
142
  decContextDefault (&context, CONTEXT_INIT);
143
  context.round = CONTEXT_ROUND;
144
 
145
  TO_INTERNAL (&a, &arg1);
146
  TO_INTERNAL (&b, &arg2);
147
 
148
  /* Perform the comparison.  */
149
  op (&res, &arg1, &arg2, &context);
150
 
151
  if (CONTEXT_TRAPS && CONTEXT_ERRORS (context))
152
    DFP_RAISE (0);
153
 
154
  if (decNumberIsNegative (&res))
155
    result = -1;
156
  else if (decNumberIsZero (&res))
157
    result = 0;
158
  else
159
    result = 1;
160
 
161
  return result;
162
}
163
 
164
 
165
#if defined(L_conv_sd)
166
void
167
__host_to_ieee_32 (_Decimal32 in, decimal32 *out)
168
{
169
  uint32_t t;
170
 
171
  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
172
    {
173
      memcpy (&t, &in, 4);
174
      t = __dec_byte_swap (t);
175
      memcpy (out, &t, 4);
176
    }
177
  else
178
    memcpy (out, &in, 4);
179
}
180
 
181
void
182
__ieee_to_host_32 (decimal32 in, _Decimal32 *out)
183
{
184
  uint32_t t;
185
 
186
  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
187
    {
188
      memcpy (&t, &in, 4);
189
      t = __dec_byte_swap (t);
190
      memcpy (out, &t, 4);
191
    }
192
  else
193
    memcpy (out, &in, 4);
194
}
195
#endif /* L_conv_sd */
196
 
197
#if defined(L_conv_dd)
198
static void
199
__swap64 (char *src, char *dst)
200
{
201
  uint32_t t1, t2;
202
 
203
  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
204
    {
205
      memcpy (&t1, src, 4);
206
      memcpy (&t2, src + 4, 4);
207
      t1 = __dec_byte_swap (t1);
208
      t2 = __dec_byte_swap (t2);
209
      memcpy (dst, &t2, 4);
210
      memcpy (dst + 4, &t1, 4);
211
    }
212
  else
213
    memcpy (dst, src, 8);
214
}
215
 
216
void
217
__host_to_ieee_64 (_Decimal64 in, decimal64 *out)
218
{
219
  __swap64 ((char *) &in, (char *) out);
220
}
221
 
222
void
223
__ieee_to_host_64 (decimal64 in, _Decimal64 *out)
224
{
225
  __swap64 ((char *) &in, (char *) out);
226
}
227
#endif /* L_conv_dd */
228
 
229
#if defined(L_conv_td)
230
static void
231
__swap128 (char *src, char *dst)
232
{
233
  uint32_t t1, t2, t3, t4;
234
 
235
  if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN)
236
    {
237
      memcpy (&t1, src, 4);
238
      memcpy (&t2, src + 4, 4);
239
      memcpy (&t3, src + 8, 4);
240
      memcpy (&t4, src + 12, 4);
241
      t1 = __dec_byte_swap (t1);
242
      t2 = __dec_byte_swap (t2);
243
      t3 = __dec_byte_swap (t3);
244
      t4 = __dec_byte_swap (t4);
245
      memcpy (dst, &t4, 4);
246
      memcpy (dst + 4, &t3, 4);
247
      memcpy (dst + 8, &t2, 4);
248
      memcpy (dst + 12, &t1, 4);
249
    }
250
  else
251
    memcpy (dst, src, 16);
252
}
253
 
254
void
255
__host_to_ieee_128 (_Decimal128 in, decimal128 *out)
256
{
257
  __swap128 ((char *) &in, (char *) out);
258
}
259
 
260
void
261
__ieee_to_host_128 (decimal128 in, _Decimal128 *out)
262
{
263
  __swap128 ((char *) &in, (char *) out);
264
}
265
#endif /* L_conv_td */
266
 
267
#if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
268
DFP_C_TYPE
269
DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
270
{
271
  return dfp_binary_op (decNumberAdd, arg_a, arg_b);
272
}
273
 
274
DFP_C_TYPE
275
DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
276
{
277
  return dfp_binary_op (decNumberSubtract, arg_a, arg_b);
278
}
279
#endif /* L_addsub */
280
 
281
#if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
282
DFP_C_TYPE
283
DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
284
{
285
  return dfp_binary_op (decNumberMultiply, arg_a, arg_b);
286
}
287
#endif /* L_mul */
288
 
289
#if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
290
DFP_C_TYPE
291
DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
292
{
293
  return dfp_binary_op (decNumberDivide, arg_a, arg_b);
294
}
295
#endif /* L_div */
296
 
297
#if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
298
CMPtype
299
DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
300
{
301
  int stat;
302
  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
303
  /* For EQ return zero for true, nonzero for false.  */
304
  return stat != 0;
305
}
306
#endif /* L_eq */
307
 
308
#if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
309
CMPtype
310
DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
311
{
312
  int stat;
313
  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
314
  /* For NE return nonzero for true, zero for false.  */
315
  return stat != 0;
316
}
317
#endif /* L_ne */
318
 
319
#if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
320
CMPtype
321
DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
322
{
323
  int stat;
324
  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
325
  /* For LT return -1 (<0) for true, 1 for false.  */
326
  return (stat == -1) ? -1 : 1;
327
}
328
#endif /* L_lt */
329
 
330
#if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
331
CMPtype
332
DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
333
{
334
  int stat;
335
  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
336
  /* For GT return 1 (>0) for true, -1 for false.  */
337
  return (stat == 1) ? 1 : -1;
338
}
339
#endif
340
 
341
#if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
342
CMPtype
343
DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
344
{
345
  int stat;
346
  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
347
  /* For LE return 0 (<= 0) for true, 1 for false.  */
348
  return stat == 1;
349
}
350
#endif /* L_le */
351
 
352
#if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
353
CMPtype
354
DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
355
{
356
  int stat;
357
  stat = dfp_compare_op (decNumberCompare, arg_a, arg_b);
358
  /* For GE return 1 (>=0) for true, -1 for false.  */
359
  return (stat != -1) ? 1 : -1;
360
}
361
#endif /* L_ge */
362
 
363
#define BUFMAX 128
364
 
365
#if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \
366
 || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd)
367
DFP_C_TYPE_TO
368
DFP_TO_DFP (DFP_C_TYPE f_from)
369
{
370
  DFP_C_TYPE_TO f_to;
371
  IEEE_TYPE s_from;
372
  IEEE_TYPE_TO s_to;
373
  decNumber d;
374
  decContext context;
375
 
376
  decContextDefault (&context, CONTEXT_INIT);
377
  context.round = CONTEXT_ROUND;
378
 
379
  HOST_TO_IEEE (f_from, &s_from);
380
  TO_INTERNAL (&s_from, &d);
381
  TO_ENCODED_TO (&s_to, &d, &context);
382
  if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
383
    DFP_RAISE (DEC_Inexact);
384
 
385
  IEEE_TO_HOST_TO (s_to, &f_to);
386
  return f_to;
387
}
388
#endif
389
 
390
#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \
391
  || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
392
  || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \
393
  || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
394
INT_TYPE
395
DFP_TO_INT (DFP_C_TYPE x)
396
{
397
  /* decNumber's decimal* types have the same format as C's _Decimal*
398
     types, but they have different calling conventions.  */
399
 
400
  IEEE_TYPE s;
401
  char buf[BUFMAX];
402
  char *pos;
403
  decNumber qval, n1, n2;
404
  decContext context;
405
 
406
  decContextDefault (&context, CONTEXT_INIT);
407
  /* Need non-default rounding mode here.  */
408
  context.round = DEC_ROUND_DOWN;
409
 
410
  HOST_TO_IEEE (x, &s);
411
  TO_INTERNAL (&s, &n1);
412
  /* Rescale if the exponent is less than zero.  */
413
  decNumberToIntegralValue (&n2, &n1, &context);
414
  /* Get a value to use for the quantize call.  */
415
  decNumberFromString (&qval, (char *) "1.0", &context);
416
  /* Force the exponent to zero.  */
417
  decNumberQuantize (&n1, &n2, &qval, &context);
418
  /* This is based on text in N1107 section 5.1; it might turn out to be
419
     undefined behavior instead.  */
420
  if (context.status & DEC_Invalid_operation)
421
    {
422
#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si)
423
      if (decNumberIsNegative(&n2))
424
        return INT_MIN;
425
      else
426
        return INT_MAX;
427
#elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di)
428
      if (decNumberIsNegative(&n2))
429
        /* Find a defined constant that will work here.  */
430
        return (-9223372036854775807LL - 1LL);
431
      else
432
        /* Find a defined constant that will work here.  */
433
        return 9223372036854775807LL;
434
#elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi)
435
      return UINT_MAX;
436
#elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
437
        /* Find a defined constant that will work here.  */
438
      return 18446744073709551615ULL;
439
#endif
440
    }
441
  /* Get a string, which at this point will not include an exponent.  */
442
  decNumberToString (&n1, buf);
443
  /* Ignore the fractional part.  */
444
  pos = strchr (buf, '.');
445
  if (pos)
446
    *pos = 0;
447
  /* Use a C library function to convert to the integral type.  */
448
  return STR_TO_INT (buf, NULL, 10);
449
}
450
#endif
451
 
452
#if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \
453
  || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
454
  || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \
455
  || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
456
DFP_C_TYPE
457
INT_TO_DFP (INT_TYPE i)
458
{
459
  DFP_C_TYPE f;
460
  IEEE_TYPE s;
461
  char buf[BUFMAX];
462
  decContext context;
463
 
464
  decContextDefault (&context, CONTEXT_INIT);
465
  context.round = CONTEXT_ROUND;
466
 
467
  /* Use a C library function to get a floating point string.  */
468
  sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i));
469
  /* Convert from the floating point string to a decimal* type.  */
470
  FROM_STRING (&s, buf, &context);
471
  IEEE_TO_HOST (s, &f);
472
  if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
473
    DFP_RAISE (DEC_Inexact);
474
  return f;
475
}
476
#endif
477
 
478
#if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
479
 || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
480
 || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
481
     && LIBGCC2_HAS_XF_MODE)
482
BFP_TYPE
483
DFP_TO_BFP (DFP_C_TYPE f)
484
{
485
  IEEE_TYPE s;
486
  char buf[BUFMAX];
487
 
488
  HOST_TO_IEEE (f, &s);
489
  /* Write the value to a string.  */
490
  TO_STRING (&s, buf);
491
  /* Read it as the binary floating point type and return that.  */
492
  return STR_TO_BFP (buf, NULL);
493
}
494
#endif
495
 
496
#if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
497
 || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
498
 || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
499
     && LIBGCC2_HAS_XF_MODE)
500
DFP_C_TYPE
501
BFP_TO_DFP (BFP_TYPE x)
502
{
503
  DFP_C_TYPE f;
504
  IEEE_TYPE s;
505
  char buf[BUFMAX];
506
  decContext context;
507
 
508
  decContextDefault (&context, CONTEXT_INIT);
509
  context.round = CONTEXT_ROUND;
510
 
511
  /* Use a C library function to write the floating point value to a string.  */
512
#ifdef BFP_VIA_TYPE
513
  /* FIXME: Is there a better way to output an XFmode variable in C?  */
514
  sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
515
#else
516
  sprintf (buf, BFP_FMT, x);
517
#endif
518
 
519
  /* Convert from the floating point string to a decimal* type.  */
520
  FROM_STRING (&s, buf, &context);
521
  IEEE_TO_HOST (s, &f);
522
  if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0)
523
    DFP_RAISE (DEC_Inexact);
524
  return f;
525
}
526
#endif
527
 
528
#if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
529
CMPtype
530
DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
531
{
532
  decNumber arg1, arg2;
533
  IEEE_TYPE a, b;
534
 
535
  HOST_TO_IEEE (arg_a, &a);
536
  HOST_TO_IEEE (arg_b, &b);
537
  TO_INTERNAL (&a, &arg1);
538
  TO_INTERNAL (&b, &arg2);
539
  return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
540
}
541
#endif /* L_unord_sd || L_unord_dd || L_unord_td */

powered by: WebSVN 2.1.0

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