1169689Skan/* Decimal floating point support.
2169689Skan   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
3169689Skan
4169689SkanThis file is part of GCC.
5169689Skan
6169689SkanGCC is free software; you can redistribute it and/or modify it under
7169689Skanthe terms of the GNU General Public License as published by the Free
8169689SkanSoftware Foundation; either version 2, or (at your option) any later
9169689Skanversion.
10169689Skan
11169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
12169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
13169689SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14169689Skanfor more details.
15169689Skan
16169689SkanYou should have received a copy of the GNU General Public License
17169689Skanalong with GCC; see the file COPYING.  If not, write to the Free
18169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19169689Skan02110-1301, USA.  */
20169689Skan
21169689Skan#include "config.h"
22169689Skan#include "system.h"
23169689Skan#include "coretypes.h"
24169689Skan#include "tm.h"
25169689Skan#include "tree.h"
26169689Skan#include "toplev.h"
27169689Skan#include "real.h"
28169689Skan#include "tm_p.h"
29169689Skan#include "dfp.h"
30169689Skan
31169689Skan/* The order of the following headers is important for making sure
32169689Skan   decNumber structure is large enough to hold decimal128 digits.  */
33169689Skan
34169689Skan#include "decimal128.h"
35169689Skan#include "decimal64.h"
36169689Skan#include "decimal32.h"
37169689Skan#include "decNumber.h"
38169689Skan
39169689Skanstatic uint32_t
40169689Skandfp_byte_swap (uint32_t in)
41169689Skan{
42169689Skan  uint32_t out = 0;
43169689Skan  unsigned char *p = (unsigned char *) &out;
44169689Skan  union {
45169689Skan    uint32_t i;
46169689Skan    unsigned char b[4];
47169689Skan  } u;
48169689Skan
49169689Skan  u.i = in;
50169689Skan  p[0] = u.b[3];
51169689Skan  p[1] = u.b[2];
52169689Skan  p[2] = u.b[1];
53169689Skan  p[3] = u.b[0];
54169689Skan
55169689Skan  return out;
56169689Skan}
57169689Skan
58169689Skan/* Initialize R (a real with the decimal flag set) from DN.  Can
59169689Skan   utilize status passed in via CONTEXT, if a previous operation had
60169689Skan   interesting status.  */
61169689Skan
62169689Skanstatic void
63169689Skandecimal_from_decnumber (REAL_VALUE_TYPE *r, decNumber *dn, decContext *context)
64169689Skan{
65169689Skan  memset (r, 0, sizeof (REAL_VALUE_TYPE));
66169689Skan
67169689Skan  r->cl = rvc_normal;
68169689Skan  if (decNumberIsZero (dn))
69169689Skan    r->cl = rvc_zero;
70169689Skan  if (decNumberIsNaN (dn))
71169689Skan    r->cl = rvc_nan;
72169689Skan  if (decNumberIsInfinite (dn))
73169689Skan    r->cl = rvc_inf;
74169689Skan  if (context->status & DEC_Overflow)
75169689Skan    r->cl = rvc_inf;
76169689Skan  if (decNumberIsNegative (dn))
77169689Skan    r->sign = 1;
78169689Skan  r->decimal = 1;
79169689Skan
80169689Skan  if (r->cl != rvc_normal)
81169689Skan    return;
82169689Skan
83169689Skan  decContextDefault (context, DEC_INIT_DECIMAL128);
84169689Skan  context->traps = 0;
85169689Skan
86169689Skan  decimal128FromNumber ((decimal128 *) r->sig, dn, context);
87169689Skan}
88169689Skan
89169689Skan/* Create decimal encoded R from string S.  */
90169689Skan
91169689Skanvoid
92169689Skandecimal_real_from_string (REAL_VALUE_TYPE *r, const char *s)
93169689Skan{
94169689Skan  decNumber dn;
95169689Skan  decContext set;
96169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
97169689Skan  set.traps = 0;
98169689Skan
99169689Skan  decNumberFromString (&dn, (char *) s, &set);
100169689Skan
101169689Skan  /* It would be more efficient to store directly in decNumber format,
102169689Skan     but that is impractical from current data structure size.
103169689Skan     Encoding as a decimal128 is much more compact.  */
104169689Skan  decimal_from_decnumber (r, &dn, &set);
105169689Skan}
106169689Skan
107169689Skan/* Initialize a decNumber from a REAL_VALUE_TYPE.  */
108169689Skan
109169689Skanstatic void
110169689Skandecimal_to_decnumber (const REAL_VALUE_TYPE *r, decNumber *dn)
111169689Skan{
112169689Skan  decContext set;
113169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
114169689Skan  set.traps = 0;
115169689Skan
116169689Skan  switch (r->cl)
117169689Skan    {
118169689Skan    case rvc_zero:
119169689Skan      decNumberZero (dn);
120169689Skan      break;
121169689Skan    case rvc_inf:
122169689Skan      decNumberFromString (dn, (char *)"Infinity", &set);
123169689Skan      break;
124169689Skan    case rvc_nan:
125169689Skan      if (r->signalling)
126169689Skan        decNumberFromString (dn, (char *)"snan", &set);
127169689Skan      else
128169689Skan        decNumberFromString (dn, (char *)"nan", &set);
129169689Skan      break;
130169689Skan    case rvc_normal:
131169689Skan      gcc_assert (r->decimal);
132169689Skan      decimal128ToNumber ((decimal128 *) r->sig, dn);
133169689Skan      break;
134169689Skan    default:
135169689Skan      gcc_unreachable ();
136169689Skan    }
137169689Skan
138169689Skan  /* Fix up sign bit.  */
139169689Skan  if (r->sign != decNumberIsNegative (dn))
140169689Skan    dn->bits ^= DECNEG;
141169689Skan}
142169689Skan
143169689Skan/* Encode a real into an IEEE 754R decimal32 type.  */
144169689Skan
145169689Skanvoid
146169689Skanencode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED,
147169689Skan		  long *buf, const REAL_VALUE_TYPE *r)
148169689Skan{
149169689Skan  decNumber dn;
150169689Skan  decimal32 d32;
151169689Skan  decContext set;
152169689Skan
153169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
154169689Skan  set.traps = 0;
155169689Skan
156169689Skan  decimal_to_decnumber (r, &dn);
157169689Skan  decimal32FromNumber (&d32, &dn, &set);
158169689Skan
159169689Skan  if (FLOAT_WORDS_BIG_ENDIAN)
160169689Skan    buf[0] = *(uint32_t *) d32.bytes;
161169689Skan  else
162169689Skan    buf[0] = dfp_byte_swap (*(uint32_t *) d32.bytes);
163169689Skan}
164169689Skan
165169689Skan/* Decode an IEEE 754R decimal32 type into a real.  */
166169689Skan
167169689Skanvoid
168169689Skandecode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED,
169169689Skan		  REAL_VALUE_TYPE *r, const long *buf)
170169689Skan{
171169689Skan  decNumber dn;
172169689Skan  decimal32 d32;
173169689Skan  decContext set;
174169689Skan
175169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
176169689Skan  set.traps = 0;
177169689Skan
178169689Skan  if (FLOAT_WORDS_BIG_ENDIAN)
179169689Skan    *((uint32_t *) d32.bytes) = (uint32_t) buf[0];
180169689Skan  else
181169689Skan    *((uint32_t *) d32.bytes) = dfp_byte_swap ((uint32_t) buf[0]);
182169689Skan
183169689Skan  decimal32ToNumber (&d32, &dn);
184169689Skan  decimal_from_decnumber (r, &dn, &set);
185169689Skan}
186169689Skan
187169689Skan/* Encode a real into an IEEE 754R decimal64 type.  */
188169689Skan
189169689Skanvoid
190169689Skanencode_decimal64 (const struct real_format *fmt ATTRIBUTE_UNUSED,
191169689Skan		  long *buf, const REAL_VALUE_TYPE *r)
192169689Skan{
193169689Skan  decNumber dn;
194169689Skan  decimal64 d64;
195169689Skan  decContext set;
196169689Skan
197169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
198169689Skan  set.traps = 0;
199169689Skan
200169689Skan  decimal_to_decnumber (r, &dn);
201169689Skan  decimal64FromNumber (&d64, &dn, &set);
202169689Skan
203169689Skan  if (FLOAT_WORDS_BIG_ENDIAN)
204169689Skan    {
205169689Skan      buf[0] = *(uint32_t *) &d64.bytes[0];
206169689Skan      buf[1] = *(uint32_t *) &d64.bytes[4];
207169689Skan    }
208169689Skan  else
209169689Skan    {
210169689Skan      buf[1] = dfp_byte_swap (*(uint32_t *) &d64.bytes[0]);
211169689Skan      buf[0] = dfp_byte_swap (*(uint32_t *) &d64.bytes[4]);
212169689Skan    }
213169689Skan}
214169689Skan
215169689Skan/* Decode an IEEE 754R decimal64 type into a real.  */
216169689Skan
217169689Skanvoid
218169689Skandecode_decimal64 (const struct real_format *fmt ATTRIBUTE_UNUSED,
219169689Skan		  REAL_VALUE_TYPE *r, const long *buf)
220169689Skan{
221169689Skan  decNumber dn;
222169689Skan  decimal64 d64;
223169689Skan  decContext set;
224169689Skan
225169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
226169689Skan  set.traps = 0;
227169689Skan
228169689Skan  if (FLOAT_WORDS_BIG_ENDIAN)
229169689Skan    {
230169689Skan      *((uint32_t *) &d64.bytes[0]) = (uint32_t) buf[0];
231169689Skan      *((uint32_t *) &d64.bytes[4]) = (uint32_t) buf[1];
232169689Skan    }
233169689Skan  else
234169689Skan    {
235169689Skan      *((uint32_t *) &d64.bytes[0]) = dfp_byte_swap ((uint32_t) buf[1]);
236169689Skan      *((uint32_t *) &d64.bytes[4]) = dfp_byte_swap ((uint32_t) buf[0]);
237169689Skan    }
238169689Skan
239169689Skan  decimal64ToNumber (&d64, &dn);
240169689Skan  decimal_from_decnumber (r, &dn, &set);
241169689Skan}
242169689Skan
243169689Skan/* Encode a real into an IEEE 754R decimal128 type.  */
244169689Skan
245169689Skanvoid
246169689Skanencode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED,
247169689Skan		   long *buf, const REAL_VALUE_TYPE *r)
248169689Skan{
249169689Skan  decNumber dn;
250169689Skan  decContext set;
251169689Skan  decimal128 d128;
252169689Skan
253169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
254169689Skan  set.traps = 0;
255169689Skan
256169689Skan  decimal_to_decnumber (r, &dn);
257169689Skan  decimal128FromNumber (&d128, &dn, &set);
258169689Skan
259169689Skan  if (FLOAT_WORDS_BIG_ENDIAN)
260169689Skan    {
261169689Skan      buf[0] = *(uint32_t *) &d128.bytes[0];
262169689Skan      buf[1] = *(uint32_t *) &d128.bytes[4];
263169689Skan      buf[2] = *(uint32_t *) &d128.bytes[8];
264169689Skan      buf[3] = *(uint32_t *) &d128.bytes[12];
265169689Skan    }
266169689Skan  else
267169689Skan    {
268169689Skan      buf[0] = dfp_byte_swap (*(uint32_t *) &d128.bytes[12]);
269169689Skan      buf[1] = dfp_byte_swap (*(uint32_t *) &d128.bytes[8]);
270169689Skan      buf[2] = dfp_byte_swap (*(uint32_t *) &d128.bytes[4]);
271169689Skan      buf[3] = dfp_byte_swap (*(uint32_t *) &d128.bytes[0]);
272169689Skan    }
273169689Skan}
274169689Skan
275169689Skan/* Decode an IEEE 754R decimal128 type into a real.  */
276169689Skan
277169689Skanvoid
278169689Skandecode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED,
279169689Skan		   REAL_VALUE_TYPE *r, const long *buf)
280169689Skan{
281169689Skan  decNumber dn;
282169689Skan  decimal128 d128;
283169689Skan  decContext set;
284169689Skan
285169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
286169689Skan  set.traps = 0;
287169689Skan
288169689Skan  if (FLOAT_WORDS_BIG_ENDIAN)
289169689Skan    {
290169689Skan      *((uint32_t *) &d128.bytes[0])  = (uint32_t) buf[0];
291169689Skan      *((uint32_t *) &d128.bytes[4])  = (uint32_t) buf[1];
292169689Skan      *((uint32_t *) &d128.bytes[8])  = (uint32_t) buf[2];
293169689Skan      *((uint32_t *) &d128.bytes[12]) = (uint32_t) buf[3];
294169689Skan    }
295169689Skan  else
296169689Skan    {
297169689Skan      *((uint32_t *) &d128.bytes[0])  = dfp_byte_swap ((uint32_t) buf[3]);
298169689Skan      *((uint32_t *) &d128.bytes[4])  = dfp_byte_swap ((uint32_t) buf[2]);
299169689Skan      *((uint32_t *) &d128.bytes[8])  = dfp_byte_swap ((uint32_t) buf[1]);
300169689Skan      *((uint32_t *) &d128.bytes[12]) = dfp_byte_swap ((uint32_t) buf[0]);
301169689Skan    }
302169689Skan
303169689Skan  decimal128ToNumber (&d128, &dn);
304169689Skan  decimal_from_decnumber (r, &dn, &set);
305169689Skan}
306169689Skan
307169689Skan/* Helper function to convert from a binary real internal
308169689Skan   representation.  */
309169689Skan
310169689Skanstatic void
311169689Skandecimal_to_binary (REAL_VALUE_TYPE *to, const REAL_VALUE_TYPE *from,
312169689Skan		   enum machine_mode mode)
313169689Skan{
314169689Skan  char string[256];
315169689Skan  decimal128 *d128;
316169689Skan  d128 = (decimal128 *) from->sig;
317169689Skan
318169689Skan  decimal128ToString (d128, string);
319169689Skan  real_from_string3 (to, string, mode);
320169689Skan}
321169689Skan
322169689Skan
323169689Skan/* Helper function to convert from a binary real internal
324169689Skan   representation.  */
325169689Skan
326169689Skanstatic void
327169689Skandecimal_from_binary (REAL_VALUE_TYPE *to, const REAL_VALUE_TYPE *from)
328169689Skan{
329169689Skan  char string[256];
330169689Skan
331169689Skan  /* We convert to string, then to decNumber then to decimal128.  */
332169689Skan  real_to_decimal (string, from, sizeof (string), 0, 1);
333169689Skan  decimal_real_from_string (to, string);
334169689Skan}
335169689Skan
336169689Skan/* Helper function to real.c:do_compare() to handle decimal internal
337169689Skan   representation including when one of the operands is still in the
338169689Skan   binary internal representation.  */
339169689Skan
340169689Skanint
341169689Skandecimal_do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b,
342169689Skan		    int nan_result)
343169689Skan{
344169689Skan  decContext set;
345169689Skan  decNumber dn, dn2, dn3;
346169689Skan  REAL_VALUE_TYPE a1, b1;
347169689Skan
348169689Skan  /* If either operand is non-decimal, create temporary versions.  */
349169689Skan  if (!a->decimal)
350169689Skan    {
351169689Skan      decimal_from_binary (&a1, a);
352169689Skan      a = &a1;
353169689Skan    }
354169689Skan  if (!b->decimal)
355169689Skan    {
356169689Skan      decimal_from_binary (&b1, b);
357169689Skan      b = &b1;
358169689Skan    }
359169689Skan
360169689Skan  /* Convert into decNumber form for comparison operation.  */
361169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
362169689Skan  set.traps = 0;
363169689Skan  decimal128ToNumber ((decimal128 *) a->sig, &dn2);
364169689Skan  decimal128ToNumber ((decimal128 *) b->sig, &dn3);
365169689Skan
366169689Skan  /* Finally, do the comparison.  */
367169689Skan  decNumberCompare (&dn, &dn2, &dn3, &set);
368169689Skan
369169689Skan  /* Return the comparison result.  */
370169689Skan  if (decNumberIsNaN (&dn))
371169689Skan    return nan_result;
372169689Skan  else if (decNumberIsZero (&dn))
373169689Skan    return 0;
374169689Skan  else if (decNumberIsNegative (&dn))
375169689Skan    return -1;
376169689Skan  else
377169689Skan    return 1;
378169689Skan}
379169689Skan
380169689Skan/* Helper to round_for_format, handling decimal float types.  */
381169689Skan
382169689Skanvoid
383169689Skandecimal_round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
384169689Skan{
385169689Skan  decNumber dn;
386169689Skan  decContext set;
387169689Skan
388169689Skan  /* Real encoding occurs later.  */
389169689Skan  if (r->cl != rvc_normal)
390169689Skan    return;
391169689Skan
392169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
393169689Skan  set.traps = 0;
394169689Skan  decimal128ToNumber ((decimal128 *) r->sig, &dn);
395169689Skan
396169689Skan  if (fmt == &decimal_quad_format)
397169689Skan    {
398169689Skan      /* The internal format is already in this format.  */
399169689Skan      return;
400169689Skan    }
401169689Skan  else if (fmt == &decimal_single_format)
402169689Skan    {
403169689Skan      decimal32 d32;
404169689Skan      decContextDefault (&set, DEC_INIT_DECIMAL32);
405169689Skan      set.traps = 0;
406169689Skan
407169689Skan      decimal32FromNumber (&d32, &dn, &set);
408169689Skan      decimal32ToNumber (&d32, &dn);
409169689Skan    }
410169689Skan  else if (fmt == &decimal_double_format)
411169689Skan    {
412169689Skan      decimal64 d64;
413169689Skan      decContextDefault (&set, DEC_INIT_DECIMAL64);
414169689Skan      set.traps = 0;
415169689Skan
416169689Skan      decimal64FromNumber (&d64, &dn, &set);
417169689Skan      decimal64ToNumber (&d64, &dn);
418169689Skan    }
419169689Skan  else
420169689Skan    gcc_unreachable ();
421169689Skan
422169689Skan  decimal_from_decnumber (r, &dn, &set);
423169689Skan}
424169689Skan
425169689Skan/* Extend or truncate to a new mode.  Handles conversions between
426169689Skan   binary and decimal types.  */
427169689Skan
428169689Skanvoid
429169689Skandecimal_real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode,
430169689Skan		      const REAL_VALUE_TYPE *a)
431169689Skan{
432169689Skan  const struct real_format *fmt = REAL_MODE_FORMAT (mode);
433169689Skan
434169689Skan  if (a->decimal && fmt->b == 10)
435169689Skan    return;
436169689Skan  if (a->decimal)
437169689Skan      decimal_to_binary (r, a, mode);
438169689Skan  else
439169689Skan      decimal_from_binary (r, a);
440169689Skan}
441169689Skan
442169689Skan/* Render R_ORIG as a decimal floating point constant.  Emit DIGITS
443169689Skan   significant digits in the result, bounded by BUF_SIZE.  If DIGITS
444169689Skan   is 0, choose the maximum for the representation.  If
445169689Skan   CROP_TRAILING_ZEROS, strip trailing zeros.  Currently, not honoring
446169689Skan   DIGITS or CROP_TRAILING_ZEROS.  */
447169689Skan
448169689Skanvoid
449169689Skandecimal_real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig,
450169689Skan			 size_t buf_size,
451169689Skan			 size_t digits ATTRIBUTE_UNUSED,
452169689Skan			 int crop_trailing_zeros ATTRIBUTE_UNUSED)
453169689Skan{
454169689Skan  decimal128 *d128 = (decimal128*) r_orig->sig;
455169689Skan
456169689Skan  /* decimal128ToString requires space for at least 24 characters;
457169689Skan     Require two more for suffix.  */
458169689Skan  gcc_assert (buf_size >= 24);
459169689Skan  decimal128ToString (d128, str);
460169689Skan}
461169689Skan
462169689Skanstatic bool
463169689Skandecimal_do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0,
464169689Skan		const REAL_VALUE_TYPE *op1, int subtract_p)
465169689Skan{
466169689Skan  decNumber dn;
467169689Skan  decContext set;
468169689Skan  decNumber dn2, dn3;
469169689Skan
470169689Skan  decimal_to_decnumber (op0, &dn2);
471169689Skan  decimal_to_decnumber (op1, &dn3);
472169689Skan
473169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
474169689Skan  set.traps = 0;
475169689Skan
476169689Skan  if (subtract_p)
477169689Skan    decNumberSubtract (&dn, &dn2, &dn3, &set);
478169689Skan  else
479169689Skan    decNumberAdd (&dn, &dn2, &dn3, &set);
480169689Skan
481169689Skan  decimal_from_decnumber (r, &dn, &set);
482169689Skan
483169689Skan  /* Return true, if inexact.  */
484169689Skan  return (set.status & DEC_Inexact);
485169689Skan}
486169689Skan
487169689Skan/* Compute R = OP0 * OP1.  */
488169689Skan
489169689Skanstatic bool
490169689Skandecimal_do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0,
491169689Skan		     const REAL_VALUE_TYPE *op1)
492169689Skan{
493169689Skan  decContext set;
494169689Skan  decNumber dn, dn2, dn3;
495169689Skan
496169689Skan  decimal_to_decnumber (op0, &dn2);
497169689Skan  decimal_to_decnumber (op1, &dn3);
498169689Skan
499169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
500169689Skan  set.traps = 0;
501169689Skan
502169689Skan  decNumberMultiply (&dn, &dn2, &dn3, &set);
503169689Skan  decimal_from_decnumber (r, &dn, &set);
504169689Skan
505169689Skan  /* Return true, if inexact.  */
506169689Skan  return (set.status & DEC_Inexact);
507169689Skan}
508169689Skan
509169689Skan/* Compute R = OP0 / OP1.  */
510169689Skan
511169689Skanstatic bool
512169689Skandecimal_do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0,
513169689Skan		   const REAL_VALUE_TYPE *op1)
514169689Skan{
515169689Skan  decContext set;
516169689Skan  decNumber dn, dn2, dn3;
517169689Skan
518169689Skan  decimal_to_decnumber (op0, &dn2);
519169689Skan  decimal_to_decnumber (op1, &dn3);
520169689Skan
521169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
522169689Skan  set.traps = 0;
523169689Skan
524169689Skan  decNumberDivide (&dn, &dn2, &dn3, &set);
525169689Skan  decimal_from_decnumber (r, &dn, &set);
526169689Skan
527169689Skan  /* Return true, if inexact.  */
528169689Skan  return (set.status & DEC_Inexact);
529169689Skan}
530169689Skan
531169689Skan/* Set R to A truncated to an integral value toward zero (decimal
532169689Skan   floating point).  */
533169689Skan
534169689Skanvoid
535169689Skandecimal_do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
536169689Skan{
537169689Skan  decNumber dn, dn2;
538169689Skan  decContext set;
539169689Skan
540169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
541169689Skan  set.traps = 0;
542169689Skan  set.round = DEC_ROUND_DOWN;
543169689Skan  decimal128ToNumber ((decimal128 *) a->sig, &dn2);
544169689Skan
545169689Skan  decNumberToIntegralValue (&dn, &dn2, &set);
546169689Skan  decimal_from_decnumber (r, &dn, &set);
547169689Skan}
548169689Skan
549169689Skan/* Render decimal float value R as an integer.  */
550169689Skan
551169689SkanHOST_WIDE_INT
552169689Skandecimal_real_to_integer (const REAL_VALUE_TYPE *r)
553169689Skan{
554169689Skan  decContext set;
555169689Skan  decNumber dn, dn2, dn3;
556169689Skan  REAL_VALUE_TYPE to;
557169689Skan  char string[256];
558169689Skan
559169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
560169689Skan  set.traps = 0;
561169689Skan  set.round = DEC_ROUND_DOWN;
562169689Skan  decimal128ToNumber ((decimal128 *) r->sig, &dn);
563169689Skan
564169689Skan  decNumberToIntegralValue (&dn2, &dn, &set);
565169689Skan  decNumberZero (&dn3);
566169689Skan  decNumberRescale (&dn, &dn2, &dn3, &set);
567169689Skan
568169689Skan  /* Convert to REAL_VALUE_TYPE and call appropriate conversion
569169689Skan     function.  */
570169689Skan  decNumberToString (&dn, string);
571169689Skan  real_from_string (&to, string);
572169689Skan  return real_to_integer (&to);
573169689Skan}
574169689Skan
575169689Skan/* Likewise, but to an integer pair, HI+LOW.  */
576169689Skan
577169689Skanvoid
578169689Skandecimal_real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
579169689Skan			  const REAL_VALUE_TYPE *r)
580169689Skan{
581169689Skan  decContext set;
582169689Skan  decNumber dn, dn2, dn3;
583169689Skan  REAL_VALUE_TYPE to;
584169689Skan  char string[256];
585169689Skan
586169689Skan  decContextDefault (&set, DEC_INIT_DECIMAL128);
587169689Skan  set.traps = 0;
588169689Skan  set.round = DEC_ROUND_DOWN;
589169689Skan  decimal128ToNumber ((decimal128 *) r->sig, &dn);
590169689Skan
591169689Skan  decNumberToIntegralValue (&dn2, &dn, &set);
592169689Skan  decNumberZero (&dn3);
593169689Skan  decNumberRescale (&dn, &dn2, &dn3, &set);
594169689Skan
595169689Skan  /* Conver to REAL_VALUE_TYPE and call appropriate conversion
596169689Skan     function.  */
597169689Skan  decNumberToString (&dn, string);
598169689Skan  real_from_string (&to, string);
599169689Skan  real_to_integer2 (plow, phigh, &to);
600169689Skan}
601169689Skan
602169689Skan/* Perform the decimal floating point operation described by CODE.
603169689Skan   For a unary operation, OP1 will be NULL.  This function returns
604169689Skan   true if the result may be inexact due to loss of precision.  */
605169689Skan
606169689Skanbool
607169689Skandecimal_real_arithmetic (REAL_VALUE_TYPE *r, enum tree_code code,
608169689Skan			 const REAL_VALUE_TYPE *op0,
609169689Skan			 const REAL_VALUE_TYPE *op1)
610169689Skan{
611169689Skan  REAL_VALUE_TYPE a, b;
612169689Skan
613169689Skan  /* If either operand is non-decimal, create temporaries.  */
614169689Skan  if (!op0->decimal)
615169689Skan    {
616169689Skan      decimal_from_binary (&a, op0);
617169689Skan      op0 = &a;
618169689Skan    }
619169689Skan  if (op1 && !op1->decimal)
620169689Skan    {
621169689Skan      decimal_from_binary (&b, op1);
622169689Skan      op1 = &b;
623169689Skan    }
624169689Skan
625169689Skan  switch (code)
626169689Skan    {
627169689Skan    case PLUS_EXPR:
628169689Skan      return decimal_do_add (r, op0, op1, 0);
629169689Skan
630169689Skan    case MINUS_EXPR:
631169689Skan      return decimal_do_add (r, op0, op1, 1);
632169689Skan
633169689Skan    case MULT_EXPR:
634169689Skan      return decimal_do_multiply (r, op0, op1);
635169689Skan
636169689Skan    case RDIV_EXPR:
637169689Skan      return decimal_do_divide (r, op0, op1);
638169689Skan
639169689Skan    case MIN_EXPR:
640169689Skan      if (op1->cl == rvc_nan)
641169689Skan        *r = *op1;
642169689Skan      else if (real_compare (UNLT_EXPR, op0, op1))
643169689Skan        *r = *op0;
644169689Skan      else
645169689Skan        *r = *op1;
646169689Skan      return false;
647169689Skan
648169689Skan    case MAX_EXPR:
649169689Skan      if (op1->cl == rvc_nan)
650169689Skan        *r = *op1;
651169689Skan      else if (real_compare (LT_EXPR, op0, op1))
652169689Skan        *r = *op1;
653169689Skan      else
654169689Skan        *r = *op0;
655169689Skan      return false;
656169689Skan
657169689Skan    case NEGATE_EXPR:
658169689Skan      {
659169689Skan	decimal128 *d128;
660169689Skan	*r = *op0;
661169689Skan	d128 = (decimal128 *) r->sig;
662169689Skan	/* Flip high bit.  */
663169689Skan	d128->bytes[0] ^= 1 << 7;
664169689Skan	/* Keep sign field in sync.  */
665169689Skan	r->sign ^= 1;
666169689Skan      }
667169689Skan      return false;
668169689Skan
669169689Skan    case ABS_EXPR:
670169689Skan      {
671169689Skan        decimal128 *d128;
672169689Skan        *r = *op0;
673169689Skan        d128 = (decimal128 *) r->sig;
674169689Skan	/* Clear high bit.  */
675169689Skan        d128->bytes[0] &= 0x7f;
676169689Skan	/* Keep sign field in sync.  */
677169689Skan	r->sign = 0;
678169689Skan      }
679169689Skan      return false;
680169689Skan
681169689Skan    case FIX_TRUNC_EXPR:
682169689Skan      decimal_do_fix_trunc (r, op0);
683169689Skan      return false;
684169689Skan
685169689Skan    default:
686169689Skan      gcc_unreachable ();
687169689Skan    }
688169689Skan}
689169689Skan
690169689Skan/* Fills R with the largest finite value representable in mode MODE.
691169689Skan   If SIGN is nonzero, R is set to the most negative finite value.  */
692169689Skan
693169689Skanvoid
694169689Skandecimal_real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
695169689Skan{
696169689Skan  char *max;
697169689Skan
698169689Skan  switch (mode)
699169689Skan    {
700169689Skan    case SDmode:
701169689Skan      max = (char *) "9.999999E96";
702169689Skan      break;
703169689Skan    case DDmode:
704169689Skan      max = (char *) "9.999999999999999E384";
705169689Skan      break;
706169689Skan    case TDmode:
707169689Skan      max = (char *) "9.999999999999999999999999999999999E6144";
708169689Skan      break;
709169689Skan    default:
710169689Skan      gcc_unreachable ();
711169689Skan    }
712169689Skan
713169689Skan  decimal_real_from_string (r, max);
714169689Skan  if (sign)
715169689Skan    r->sig[0] |= 0x80000000;
716169689Skan}
717