1169695Skan/* Utility functions for decimal floating point support via decNumber.
2169695Skan   Copyright (C) 2005 Free Software Foundation, Inc.
3169695Skan   Contributed by IBM Corporation.  Author Mike Cowlishaw.
4169695Skan
5169695Skan   This file is part of GCC.
6169695Skan
7169695Skan   GCC is free software; you can redistribute it and/or modify it under
8169695Skan   the terms of the GNU General Public License as published by the Free
9169695Skan   Software Foundation; either version 2, or (at your option) any later
10169695Skan   version.
11169695Skan
12169695Skan   In addition to the permissions in the GNU General Public License,
13169695Skan   the Free Software Foundation gives you unlimited permission to link
14169695Skan   the compiled version of this file into combinations with other
15169695Skan   programs, and to distribute those combinations without any
16169695Skan   restriction coming from the use of this file.  (The General Public
17169695Skan   License restrictions do apply in other respects; for example, they
18169695Skan   cover modification of the file, and distribution when not linked
19169695Skan   into a combine executable.)
20169695Skan
21169695Skan   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
22169695Skan   WARRANTY; without even the implied warranty of MERCHANTABILITY or
23169695Skan   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24169695Skan   for more details.
25169695Skan
26169695Skan   You should have received a copy of the GNU General Public License
27169695Skan   along with GCC; see the file COPYING.  If not, write to the Free
28169695Skan   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29169695Skan   02110-1301, USA.  */
30169695Skan
31169695Skan#include "config.h"
32169695Skan#include "decNumber.h"          /* base number library */
33169695Skan#include "decNumberLocal.h"     /* decNumber local types, etc. */
34169695Skan#include "decUtility.h"         /* utility routines */
35169695Skan
36169695Skan/* ================================================================== */
37169695Skan/* Shared utility routines                                            */
38169695Skan/* ================================================================== */
39169695Skan
40169695Skan/* define and include the conversion tables to use */
41169695Skan#define DEC_BIN2DPD 1		/* used for all sizes */
42169695Skan#if DECDPUN==3
43169695Skan#define DEC_DPD2BIN 1
44169695Skan#else
45169695Skan#define DEC_DPD2BCD 1
46169695Skan#endif
47169695Skan#include "decDPD.h"		/* lookup tables */
48169695Skan
49169695Skan/* The maximum number of decNumberUnits we need for a working copy of */
50169695Skan/* the units array is the ceiling of digits/DECDPUN, where digits is */
51169695Skan/* the maximum number of digits in any of the formats for which this */
52169695Skan/* is used.  We do not want to include decimal128.h, so, as a very */
53169695Skan/* special case, that number is defined here. */
54169695Skan#define DECMAX754   34
55169695Skan#define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN)
56169695Skan
57169695Skan/* ------------------------------------------------------------------ */
58169695Skan/* decDensePackCoeff -- densely pack coefficient into DPD form        */
59169695Skan/*                                                                    */
60169695Skan/*   dn is the source number (assumed valid, max DECMAX754 digits)    */
61169695Skan/*   bytes is the target's byte array                                 */
62169695Skan/*   len is length of target format's byte array                      */
63169695Skan/*   shift is the number of 0 digits to add on the right (normally 0) */
64169695Skan/*                                                                    */
65169695Skan/* The coefficient must be known small enough to fit, and is filled   */
66169695Skan/* in from the right (least significant first).  Note that the full   */
67169695Skan/* coefficient is copied, including the leading 'odd' digit.  This    */
68169695Skan/* digit is retrieved and packed into the combination field by the    */
69169695Skan/* caller.                                                            */
70169695Skan/*                                                                    */
71169695Skan/* shift is used for 'fold-down' padding.                             */
72169695Skan/*                                                                    */
73169695Skan/* No error is possible.                                              */
74169695Skan/* ------------------------------------------------------------------ */
75169695Skanvoid
76169695SkandecDensePackCoeff (const decNumber * dn, uByte * bytes, Int len, Int shift)
77169695Skan{
78169695Skan  Int cut;			/* work */
79169695Skan  Int n;			/* output bunch counter */
80169695Skan  Int digits = dn->digits;	/* digit countdown */
81169695Skan  uInt dpd;			/* densely packed decimal value */
82169695Skan  uInt bin;			/* binary value 0-999 */
83169695Skan  uByte *bout;			/* -> current output byte */
84169695Skan  const Unit *inu = dn->lsu;	/* -> current input unit */
85169695Skan  Unit uar[DECMAXUNITS];	/* working copy of units, iff shifted */
86169695Skan#if DECDPUN!=3			/* not fast path */
87169695Skan  Unit in;			/* current input unit */
88169695Skan#endif
89169695Skan
90169695Skan  if (shift != 0)
91169695Skan    {				/* shift towards most significant required */
92169695Skan      /* shift the units array to the left by pad digits and copy */
93169695Skan      /* [this code is a special case of decShiftToMost, which could */
94169695Skan      /* be used instead if exposed and the array were copied first] */
95169695Skan      Unit *target, *first;	/* work */
96169695Skan      const Unit *source;	/* work */
97169695Skan      uInt next = 0;		/* work */
98169695Skan
99169695Skan      source = dn->lsu + D2U (digits) - 1;	/* where msu comes from */
100169695Skan      first = uar + D2U (digits + shift) - 1;	/* where msu will end up */
101169695Skan      target = uar + D2U (digits) - 1 + D2U (shift);	/* where upper part of first cut goes */
102169695Skan
103169695Skan      cut = (DECDPUN - shift % DECDPUN) % DECDPUN;
104169695Skan      for (; source >= dn->lsu; source--, target--)
105169695Skan	{
106169695Skan	  /* split the source Unit and accumulate remainder for next */
107169695Skan	  uInt rem = *source % powers[cut];
108169695Skan	  next += *source / powers[cut];
109169695Skan	  if (target <= first)
110169695Skan	    *target = (Unit) next;	/* write to target iff valid */
111169695Skan	  next = rem * powers[DECDPUN - cut];	/* save remainder for next Unit */
112169695Skan	}
113169695Skan      /* propagate remainder to one below and clear the rest */
114169695Skan      for (; target >= uar; target--)
115169695Skan	{
116169695Skan	  *target = (Unit) next;
117169695Skan	  next = 0;
118169695Skan	}
119169695Skan      digits += shift;		/* add count (shift) of zeros added */
120169695Skan      inu = uar;		/* use units in working array */
121169695Skan    }
122169695Skan
123169695Skan  /* densely pack the coefficient into the byte array, starting from
124169695Skan     the right (optionally padded) */
125169695Skan  bout = &bytes[len - 1];	/* rightmost result byte for phase */
126169695Skan
127169695Skan#if DECDPUN!=3			/* not fast path */
128169695Skan  in = *inu;			/* prime */
129169695Skan  cut = 0;			/* at lowest digit */
130169695Skan  bin = 0;			/* [keep compiler quiet] */
131169695Skan#endif
132169695Skan
133169695Skan  for (n = 0; digits > 0; n++)
134169695Skan    {				/* each output bunch */
135169695Skan#if DECDPUN==3			/* fast path, 3-at-a-time */
136169695Skan      bin = *inu;		/* 3 ready for convert */
137169695Skan      digits -= 3;		/* [may go negative] */
138169695Skan      inu++;			/* may need another */
139169695Skan
140169695Skan#else /* must collect digit-by-digit */
141169695Skan      Unit dig;			/* current digit */
142169695Skan      Int j;			/* digit-in-bunch count */
143169695Skan      for (j = 0; j < 3; j++)
144169695Skan	{
145169695Skan#if DECDPUN<=4
146169695Skan	  Unit temp = (Unit) ((uInt) (in * 6554) >> 16);
147169695Skan	  dig = (Unit) (in - X10 (temp));
148169695Skan	  in = temp;
149169695Skan#else
150169695Skan	  dig = in % 10;
151169695Skan	  in = in / 10;
152169695Skan#endif
153169695Skan
154169695Skan	  if (j == 0)
155169695Skan	    bin = dig;
156169695Skan	  else if (j == 1)
157169695Skan	    bin += X10 (dig);
158169695Skan	  else			/* j==2 */
159169695Skan	    bin += X100 (dig);
160169695Skan
161169695Skan	  digits--;
162169695Skan	  if (digits == 0)
163169695Skan	    break;		/* [also protects *inu below] */
164169695Skan	  cut++;
165169695Skan	  if (cut == DECDPUN)
166169695Skan	    {
167169695Skan	      inu++;
168169695Skan	      in = *inu;
169169695Skan	      cut = 0;
170169695Skan	    }
171169695Skan	}
172169695Skan#endif
173169695Skan      /* here we have 3 digits in bin, or have used all input digits */
174169695Skan
175169695Skan      dpd = BIN2DPD[bin];
176169695Skan
177169695Skan      /* write bunch (bcd) to byte array */
178169695Skan      switch (n & 0x03)
179169695Skan	{			/* phase 0-3 */
180169695Skan	case 0:
181169695Skan	  *bout = (uByte) dpd;	/* [top 2 bits truncated] */
182169695Skan	  bout--;
183169695Skan	  *bout = (uByte) (dpd >> 8);
184169695Skan	  break;
185169695Skan	case 1:
186169695Skan	  *bout |= (uByte) (dpd << 2);
187169695Skan	  bout--;
188169695Skan	  *bout = (uByte) (dpd >> 6);
189169695Skan	  break;
190169695Skan	case 2:
191169695Skan	  *bout |= (uByte) (dpd << 4);
192169695Skan	  bout--;
193169695Skan	  *bout = (uByte) (dpd >> 4);
194169695Skan	  break;
195169695Skan	case 3:
196169695Skan	  *bout |= (uByte) (dpd << 6);
197169695Skan	  bout--;
198169695Skan	  *bout = (uByte) (dpd >> 2);
199169695Skan	  bout--;
200169695Skan	  break;
201169695Skan	}			/* switch */
202169695Skan    }				/* n bunches */
203169695Skan  return;
204169695Skan}
205169695Skan
206169695Skan/* ------------------------------------------------------------------ */
207169695Skan/* decDenseUnpackCoeff -- unpack a format's coefficient               */
208169695Skan/*                                                                    */
209169695Skan/*   byte is the source's byte array                                  */
210169695Skan/*   len is length of the source's byte array                         */
211169695Skan/*   dn is the target number, with 7, 16, or 34-digit space.          */
212169695Skan/*   bunches is the count of DPD groups in the decNumber (2, 5, or 11)*/
213169695Skan/*   odd is 1 if there is a non-zero leading 10-bit group containing  */
214169695Skan/*     a single digit, 0 otherwise                                    */
215169695Skan/*                                                                    */
216169695Skan/* (This routine works on a copy of the number, if necessary, where   */
217169695Skan/* an extra 10-bit group is prefixed to the coefficient continuation  */
218169695Skan/* to hold the most significant digit if the latter is non-0.)        */
219169695Skan/*                                                                    */
220169695Skan/* dn->digits is set, but not the sign or exponent.                   */
221169695Skan/* No error is possible [the redundant 888 codes are allowed].        */
222169695Skan/* ------------------------------------------------------------------ */
223169695Skanvoid
224169695SkandecDenseUnpackCoeff (const uByte * bytes, Int len, decNumber * dn,
225169695Skan		     Int bunches, Int odd)
226169695Skan{
227169695Skan  uInt dpd = 0;			/* collector for 10 bits */
228169695Skan  Int n;			/* counter */
229169695Skan  const uByte *bin;		/* -> current input byte */
230169695Skan  Unit *uout = dn->lsu;		/* -> current output unit */
231169695Skan  Unit out = 0;			/* accumulator */
232169695Skan  Int cut = 0;			/* power of ten in current unit */
233169695Skan  Unit *last = uout;		/* will be unit containing msd */
234169695Skan#if DECDPUN!=3
235169695Skan  uInt bcd;			/* BCD result */
236169695Skan  uInt nibble;			/* work */
237169695Skan#endif
238169695Skan
239169695Skan  /* Expand the densely-packed integer, right to left */
240169695Skan  bin = &bytes[len - 1];	/* next input byte to use */
241169695Skan  for (n = 0; n < bunches + odd; n++)
242169695Skan    {				/* N bunches of 10 bits */
243169695Skan      /* assemble the 10 bits */
244169695Skan      switch (n & 0x03)
245169695Skan	{			/* phase 0-3 */
246169695Skan	case 0:
247169695Skan	  dpd = *bin;
248169695Skan	  bin--;
249169695Skan	  dpd |= (*bin & 0x03) << 8;
250169695Skan	  break;
251169695Skan	case 1:
252169695Skan	  dpd = (unsigned) *bin >> 2;
253169695Skan	  bin--;
254169695Skan	  dpd |= (*bin & 0x0F) << 6;
255169695Skan	  break;
256169695Skan	case 2:
257169695Skan	  dpd = (unsigned) *bin >> 4;
258169695Skan	  bin--;
259169695Skan	  dpd |= (*bin & 0x3F) << 4;
260169695Skan	  break;
261169695Skan	case 3:
262169695Skan	  dpd = (unsigned) *bin >> 6;
263169695Skan	  bin--;
264169695Skan	  dpd |= (*bin) << 2;
265169695Skan	  bin--;
266169695Skan	  break;
267169695Skan	}			/*switch */
268169695Skan
269169695Skan#if DECDPUN==3
270169695Skan      if (dpd == 0)
271169695Skan	*uout = 0;
272169695Skan      else
273169695Skan	{
274169695Skan	  *uout = DPD2BIN[dpd];	/* convert 10 bits to binary 0-999 */
275169695Skan	  last = uout;		/* record most significant unit */
276169695Skan	}
277169695Skan      uout++;
278169695Skan
279169695Skan#else /* DECDPUN!=3 */
280169695Skan      if (dpd == 0)
281169695Skan	{			/* fastpath [e.g., leading zeros] */
282169695Skan	  cut += 3;
283169695Skan	  for (; cut >= DECDPUN;)
284169695Skan	    {
285169695Skan	      cut -= DECDPUN;
286169695Skan	      *uout = out;
287169695Skan	      uout++;
288169695Skan	      out = 0;
289169695Skan	    }
290169695Skan	  continue;
291169695Skan	}
292169695Skan      bcd = DPD2BCD[dpd];	/* convert 10 bits to 12 bits BCD */
293169695Skan      /* now split the 3 BCD nibbles into bytes, and accumulate into units */
294169695Skan      /* If this is the last bunch and it is an odd one, we only have one */
295169695Skan      /* nibble to handle [extras could overflow a Unit] */
296169695Skan      nibble = bcd & 0x000f;
297169695Skan      if (nibble)
298169695Skan	{
299169695Skan	  last = uout;
300169695Skan	  out = (Unit) (out + nibble * powers[cut]);
301169695Skan	}
302169695Skan      cut++;
303169695Skan      if (cut == DECDPUN)
304169695Skan	{
305169695Skan	  *uout = out;
306169695Skan	  uout++;
307169695Skan	  cut = 0;
308169695Skan	  out = 0;
309169695Skan	}
310169695Skan      if (n < bunches)
311169695Skan	{
312169695Skan	  nibble = bcd & 0x00f0;
313169695Skan	  if (nibble)
314169695Skan	    {
315169695Skan	      nibble >>= 4;
316169695Skan	      last = uout;
317169695Skan	      out = (Unit) (out + nibble * powers[cut]);
318169695Skan	    }
319169695Skan	  cut++;
320169695Skan	  if (cut == DECDPUN)
321169695Skan	    {
322169695Skan	      *uout = out;
323169695Skan	      uout++;
324169695Skan	      cut = 0;
325169695Skan	      out = 0;
326169695Skan	    }
327169695Skan	  nibble = bcd & 0x0f00;
328169695Skan	  if (nibble)
329169695Skan	    {
330169695Skan	      nibble >>= 8;
331169695Skan	      last = uout;
332169695Skan	      out = (Unit) (out + nibble * powers[cut]);
333169695Skan	    }
334169695Skan	  cut++;
335169695Skan	  if (cut == DECDPUN)
336169695Skan	    {
337169695Skan	      *uout = out;
338169695Skan	      uout++;
339169695Skan	      cut = 0;
340169695Skan	      out = 0;
341169695Skan	    }
342169695Skan	}
343169695Skan#endif
344169695Skan    }				/* n */
345169695Skan  if (cut != 0)
346169695Skan    *uout = out;		/* write out final unit */
347169695Skan
348169695Skan  /* here, last points to the most significant unit with digits */
349169695Skan  /* we need to inspect it to get final digits count */
350169695Skan  dn->digits = (last - dn->lsu) * DECDPUN;	/* floor of digits */
351169695Skan  for (cut = 0; cut < DECDPUN; cut++)
352169695Skan    {
353169695Skan      if (*last < powers[cut])
354169695Skan	break;
355169695Skan      dn->digits++;
356169695Skan    }
357169695Skan  if (dn->digits == 0)
358169695Skan    dn->digits++;		/* zero has one digit */
359169695Skan  return;
360169695Skan}
361