1/* This is a software decimal floating point library. 2 Copyright (C) 2005, 2006 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 2, or (at your option) any later 9version. 10 11In addition to the permissions in the GNU General Public License, the 12Free Software Foundation gives you unlimited permission to link the 13compiled version of this file into combinations with other programs, 14and to distribute those combinations without any restriction coming 15from the use of this file. (The General Public License restrictions 16do apply in other respects; for example, they cover modification of 17the file, and distribution when not linked into a combine 18executable.) 19 20GCC is distributed in the hope that it will be useful, but WITHOUT ANY 21WARRANTY; without even the implied warranty of MERCHANTABILITY or 22FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 23for more details. 24 25You should have received a copy of the GNU General Public License 26along with GCC; see the file COPYING. If not, write to the Free 27Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 2802110-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 49void __host_to_ieee_32 (_Decimal32 in, decimal32 *out); 50void __ieee_to_host_32 (decimal32 in, _Decimal32 *out); 51#endif 52#if WIDTH == 64 || WIDTH_TO == 64 53void __host_to_ieee_64 (_Decimal64 in, decimal64 *out); 54void __ieee_to_host_64 (decimal64 in, _Decimal64 *out); 55#endif 56#if WIDTH == 128 || WIDTH_TO == 128 57void __host_to_ieee_128 (_Decimal128 in, decimal128 *out); 58void __ieee_to_host_128 (decimal128 in, _Decimal128 *out); 59#endif 60 61/* A pointer to a unary decNumber operation. */ 62typedef decNumber* (*dfp_unary_func) 63 (decNumber *, decNumber *, decContext *); 64 65/* A pointer to a binary decNumber operation. */ 66typedef decNumber* (*dfp_binary_func) 67 (decNumber *, decNumber *, decNumber *, decContext *); 68 69extern unsigned long __dec_byte_swap (unsigned long); 70 71/* Unary operations. */ 72 73static inline DFP_C_TYPE 74dfp_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 101static inline DFP_C_TYPE 102dfp_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 131static inline int 132dfp_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) 166void 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 181void 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) 198static 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 216void 217__host_to_ieee_64 (_Decimal64 in, decimal64 *out) 218{ 219 __swap64 ((char *) &in, (char *) out); 220} 221 222void 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) 230static 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 254void 255__host_to_ieee_128 (_Decimal128 in, decimal128 *out) 256{ 257 __swap128 ((char *) &in, (char *) out); 258} 259 260void 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) 268DFP_C_TYPE 269DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 270{ 271 return dfp_binary_op (decNumberAdd, arg_a, arg_b); 272} 273 274DFP_C_TYPE 275DFP_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) 282DFP_C_TYPE 283DFP_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) 290DFP_C_TYPE 291DFP_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) 298CMPtype 299DFP_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) 309CMPtype 310DFP_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) 320CMPtype 321DFP_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) 331CMPtype 332DFP_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) 342CMPtype 343DFP_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) 353CMPtype 354DFP_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) 367DFP_C_TYPE_TO 368DFP_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) 394INT_TYPE 395DFP_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) 456DFP_C_TYPE 457INT_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) 482BFP_TYPE 483DFP_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) 500DFP_C_TYPE 501BFP_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) 529CMPtype 530DFP_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 */ 542