test_dfp5.c revision 663860b1408516d02ebfcb3a9999a134e6cfb223
1/*  Copyright (C) 2012 IBM
2
3 Author: Maynard Johnson <maynardj@us.ibm.com>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307, USA.
19
20 The GNU General Public License is contained in the file COPYING.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <stdint.h>
26
27#if defined(HAS_DFP)
28
29typedef union stuff {
30   _Decimal64  dec_val;
31   _Decimal128  dec_val128;
32   unsigned long long u64_val;
33   struct {
34      unsigned long long valu;
35      unsigned long long vall;
36   } u128;
37} dfp_val_t;
38
39
40typedef unsigned char Bool;
41#define True 1
42#define False 0
43
44
45#define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
46
47#define SET_CR(_arg) \
48      __asm__ __volatile__ ("mtcr  %0" : : "b"(_arg) : ALLCR );
49
50#define SET_XER(_arg) \
51      __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
52
53#define GET_CR(_lval) \
54      __asm__ __volatile__ ("mfcr %0"  : "=b"(_lval) )
55
56#define GET_XER(_lval) \
57      __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
58
59#define GET_CR_XER(_lval_cr,_lval_xer) \
60   do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0)
61
62#define SET_CR_ZERO \
63      SET_CR(0)
64
65#define SET_XER_ZERO \
66      SET_XER(0)
67
68#define SET_CR_XER_ZERO \
69   do { SET_CR_ZERO; SET_XER_ZERO; } while (0)
70
71#define SET_FPSCR_ZERO \
72   do { double _d = 0.0; \
73        __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
74   } while (0)
75
76#define GET_FPSCR(_arg) \
77    __asm__ __volatile__ ("mffs %0"  : "=f"(_arg) )
78
79#define SET_FPSCR_DRN \
80    __asm__ __volatile__ ("mtfsf  1, %0, 0, 1" :  : "f"(f14) )
81
82#ifndef __powerpc64__
83typedef uint32_t HWord_t;
84#else
85typedef uint64_t HWord_t;
86#endif /* __powerpc64__ */
87
88enum BF_vals { BF_val1 = 0, BF_val2 = 1, BF_val3 =6};
89
90// The assembly-level instructions being tested
91static void _test_dtstsf(unsigned int BF, unsigned int ref_sig, dfp_val_t valB)
92{
93   _Decimal64 f16 = valB.dec_val;
94   register HWord_t r14 __asm__ ("r14");
95   double f14;
96   r14 = (HWord_t)&ref_sig;
97
98   __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14));
99   switch (BF) {
100      case BF_val1:
101         __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16));
102         break;
103      case BF_val2:
104         __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16));
105         break;
106      case BF_val3:
107         __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16));
108         break;
109      default:
110         fprintf(stderr, "Invalid value %d for BF\n", BF);
111         break;
112   }
113}
114
115static void _test_dtstsfq(unsigned int BF, unsigned int ref_sig, dfp_val_t valB)
116{
117   _Decimal128 f16 = valB.dec_val128;
118   register HWord_t r14 __asm__ ("r14");
119   double f14;
120   r14 = (HWord_t)&ref_sig;
121
122   __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14));
123   switch (BF) {
124      case BF_val1:
125         __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16));
126         break;
127      case BF_val2:
128         __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16));
129         break;
130      case BF_val3:
131         __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16));
132         break;
133      default:
134         fprintf(stderr, "Invalid value %d for BF\n", BF);
135         break;
136   }
137}
138
139static dfp_val_t _test_ddedpd(unsigned int SP, dfp_val_t valB)
140{
141   _Decimal64 ret = 0;
142   dfp_val_t result;
143   _Decimal64 f16 = valB.dec_val;
144   switch (SP) {
145      case 0:
146         __asm__ __volatile__ ("ddedpd. 0, %0, %1" : "=f" (ret) : "f" (f16));
147         break;
148      case 1:
149         __asm__ __volatile__ ("ddedpd. 1, %0, %1" : "=f" (ret) : "f" (f16));
150         break;
151      case 2:
152         __asm__ __volatile__ ("ddedpd. 2, %0, %1" : "=f" (ret) : "f" (f16));
153         break;
154      case 3:
155         __asm__ __volatile__ ("ddedpd. 3, %0, %1" : "=f" (ret) : "f" (f16));
156         break;
157      default:
158         fprintf(stderr, "Invalid value %d for SP\n", SP);
159         break;
160   }
161   result.dec_val = ret;
162   return result;
163}
164
165
166static dfp_val_t _test_ddedpdq(unsigned int SP, dfp_val_t valB)
167{
168   _Decimal128 ret = 0;
169   dfp_val_t result;
170   _Decimal128 f16 = valB.dec_val128;
171   switch (SP) {
172      case 0:
173         __asm__ __volatile__ ("ddedpdq 0, %0, %1" : "=f" (ret) : "f" (f16));
174         break;
175      case 1:
176         __asm__ __volatile__ ("ddedpdq 1, %0, %1" : "=f" (ret) : "f" (f16));
177         break;
178      case 2:
179         __asm__ __volatile__ ("ddedpdq 2, %0, %1" : "=f" (ret) : "f" (f16));
180         break;
181      case 3:
182         __asm__ __volatile__ ("ddedpdq 3, %0, %1" : "=f" (ret) : "f" (f16));
183         break;
184      default:
185         fprintf(stderr, "Invalid value %d for SP\n", SP);
186         break;
187   }
188   result.dec_val128 = ret;
189   return result;
190}
191
192static dfp_val_t _test_denbcd(unsigned int S, dfp_val_t valB)
193{
194   _Decimal64 ret = 0;
195   dfp_val_t result;
196   _Decimal64 f16 = valB.dec_val;
197   switch (S) {
198      case 0:
199         __asm__ __volatile__ ("denbcd. 0, %0, %1" : "=f" (ret) : "f" (f16));
200         break;
201      case 1:
202         __asm__ __volatile__ ("denbcd. 1, %0, %1" : "=f" (ret) : "f" (f16));
203         break;
204      default:
205         fprintf(stderr, "Invalid value %d for S\n", S);
206         break;
207   }
208   result.dec_val = ret;
209   return result;
210}
211
212
213static dfp_val_t _test_denbcdq(unsigned int S, dfp_val_t valB)
214{
215   _Decimal128 ret = 0;
216   dfp_val_t result;
217   _Decimal128 f16 = valB.dec_val128;
218   switch (S) {
219      case 0:
220         __asm__ __volatile__ ("denbcdq 0, %0, %1" : "=f" (ret) : "f" (f16));
221         break;
222      case 1:
223         __asm__ __volatile__ ("denbcdq 1, %0, %1" : "=f" (ret) : "f" (f16));
224         break;
225      default:
226         fprintf(stderr, "Invalid value %d for S\n", S);
227         break;
228   }
229   result.dec_val128 = ret;
230   return result;
231}
232
233
234typedef void (*test_func_t)(unsigned int imm, unsigned int imm2,  dfp_val_t valB);
235typedef dfp_val_t (*test_func_bcd_t)(unsigned int imm, dfp_val_t valB);
236typedef void (*test_driver_func_t)(void);
237typedef struct test_table
238{
239   test_driver_func_t test_category;
240   char * name;
241} test_table_t;
242
243/*
244 *  345.0DD (0x2207c00000000000 0xe50)
245 *  1.2300e+5DD (0x2207c00000000000 0x14c000)
246 *  -16.0DD (0xa207c00000000000 0xe0)
247 *  0.00189DD (0x2206c00000000000 0xcf)
248 *  -4.1235DD (0xa205c00000000000 0x10a395bcf)
249 *  9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
250 *  0DD (0x2208000000000000 0x0)
251 *  0DD (0x2208000000000000 0x0)
252 *  infDD (0x7800000000000000 0x0)
253 *  nanDD (0x7c00000000000000 0x0
254 */
255static unsigned long long dfp128_vals[] = {
256                                    // Some finite numbers
257                                    0x2207c00000000000ULL, 0x0000000000000e50ULL,
258                                    0x2207c00000000000ULL, 0x000000000014c000ULL,
259                                    0xa207c00000000000ULL, 0x00000000000000e0ULL,
260                                    0x2206c00000000000ULL, 0x00000000000000cfULL,
261                                    0xa205c00000000000ULL, 0x000000010a395bcfULL,
262                                    0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
263                                    0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
264                                    // flavors of zero
265                                    0x2208000000000000ULL, 0x0000000000000000ULL,
266                                    0xa208000000000000ULL, 0x0000000000000000ULL, // negative
267                                    0xa248000000000000ULL, 0x0000000000000000ULL,
268                                    // flavors of NAN
269                                    0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
270                                    0xfc00000000000000ULL, 0xc00100035b007700ULL,
271                                    0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
272                                    // flavors of Infinity
273                                    0x7800000000000000ULL, 0x0000000000000000ULL,
274                                    0xf800000000000000ULL, 0x0000000000000000ULL, // negative
275                                    0xf900000000000000ULL, 0x0000000000000000ULL
276};
277
278static unsigned long long dfp64_vals[] = {
279                                 // various finite numbers
280                                 0x2234000000000e50ULL,
281                                 0x223400000014c000ULL,
282                                 0xa2340000000000e0ULL,// negative
283                                 0x22240000000000cfULL,
284                                 0xa21400010a395bcfULL,// negative
285                                 0x6e4d3f1f534acdd4ULL,// huge number
286                                 0x000400000089b000ULL,// very small number
287                                 // flavors of zero
288                                 0x2238000000000000ULL,
289                                 0xa238000000000000ULL,
290                                 0x4248000000000000ULL,
291                                 // flavors of NAN
292                                 0x7e34000000000111ULL,
293                                 0xfe000000d0e0a0d0ULL,//signaling
294                                 0xfc00000000000000ULL,//quiet
295                                 // flavors of Infinity
296                                 0x7800000000000000ULL,
297                                 0xf800000000000000ULL,//negative
298                                 0x7a34000000000000ULL,
299};
300
301/* The bcd64_vals and bdc128_vals hold the unique results of executing
302 * the ddedpd instruction on the basic dfp64 and dfp128 array values.
303 * Executing the inverse operation (denbcd) on these values with the
304 * appropriate S (signed) value should yield values approximating the
305 * original dfp values (except being 2^4 in magnitude since the decoding
306 * operation shifted the value one hex digit to the left to make room
307 * for signedness info).
308 */
309static unsigned long long bcd64_vals[] = {
310                                          0x0000000000003450ULL,
311                                          0x000000000003450cULL,
312                                          0x000000000003450fULL,
313                                          0x0000000001230000ULL,
314                                          0x000000001230000cULL,
315                                          0x000000001230000fULL,
316                                          0x0000000000000160ULL,
317                                          0x000000000000160dULL,
318                                          0x0000000000000189ULL,
319                                          0x000000000000189cULL,
320                                          0x000000000000189fULL,
321                                          0x0000004123456789ULL,
322                                          0x000004123456789dULL,
323                                          0x9839871234533354ULL,
324                                          0x839871234533354cULL,
325                                          0x839871234533354fULL,
326                                          0x0000000008864000ULL,
327                                          0x000000008864000cULL,
328                                          0x000000008864000fULL,
329                                          0x0000000000000000ULL,
330                                          0x000000000000000cULL,
331                                          0x000000000000000fULL,
332                                          0x000000000000000dULL,
333                                          0x0000000000000211ULL,
334                                          0x000000000000211cULL,
335                                          0x000000000000211fULL,
336                                          0x0000003882028150ULL,
337                                          0x000003882028150dULL
338 };
339
340static unsigned long long bcd128_vals[] = {
341                                           0x0000000000000000ULL, 0x0000000000003450ULL,
342                                           0x0000000000000000ULL, 0x000000000003450cULL,
343                                           0x0000000000000000ULL, 0x000000000003450fULL,
344                                           0x0000000000000000ULL, 0x0000000001230000ULL,
345                                           0x0000000000000000ULL, 0x000000001230000cULL,
346                                           0x0000000000000000ULL, 0x000000001230000fULL,
347                                           0x0000000000000000ULL, 0x0000000000000160ULL,
348                                           0x0000000000000000ULL, 0x000000000000160dULL,
349                                           0x0000000000000000ULL, 0x0000000000000189ULL,
350                                           0x0000000000000000ULL, 0x000000000000189cULL,
351                                           0x0000000000000000ULL, 0x000000000000189fULL,
352                                           0x0000000000000000ULL, 0x0000004123456789ULL,
353                                           0x0000000000000000ULL, 0x000004123456789dULL,
354                                           0x0000097100000000ULL, 0x9839871234533354ULL,
355                                           0x0000971000000009ULL, 0x839871234533354cULL,
356                                           0x0000971000000009ULL, 0x839871234533354fULL,
357                                           0x0000010954000051ULL, 0x8000640000000049ULL,
358                                           0x0000109540000518ULL, 0x000640000000049cULL,
359                                           0x0000109540000518ULL, 0x000640000000049fULL,
360                                           0x0000000000000000ULL, 0x0000000000000000ULL,
361                                           0x0000000000000000ULL, 0x000000000000000cULL,
362                                           0x0000000000000000ULL, 0x000000000000000fULL,
363                                           0x0000000000000000ULL, 0x000000000000000dULL,
364                                           0x0000000000080000ULL, 0x0200801330811600ULL,
365                                           0x0000000000800000ULL, 0x200801330811600dULL,
366                                           0x0000000000088170ULL, 0x0000003882028150ULL,
367                                           0x0000000000881700ULL, 0x000003882028150cULL,
368                                           0x0000000000881700ULL, 0x000003882028150fULL
369};
370
371// Both Long and Quad arrays of DFP values should have the same length, so it
372// doesn't matter which array I use for calculating the following #define.
373#define NUM_DFP_VALS (sizeof(dfp64_vals)/8)
374
375typedef enum {
376   LONG_TEST,
377   QUAD_TEST
378} precision_type_t;
379
380typedef struct dfp_one_arg_test
381{
382   test_func_t test_func;
383   const char * name;
384   precision_type_t precision;
385   const char * op;
386} dfp_one_arg_test_t;
387
388typedef struct dfp_one_arg_bcd_test
389{
390   test_func_bcd_t test_func;
391   const char * name;
392   precision_type_t precision;
393   const char * op;
394} dfp_one_arg_bcd_test_t;
395
396static dfp_one_arg_bcd_test_t
397dfp_test_dfp_ddedpd_tests[] = {
398                            { &_test_ddedpd, "ddedpd", LONG_TEST, "[D->B]"},
399                            { &_test_ddedpdq, "ddedpdq", QUAD_TEST, "[D->B]"},
400                            { NULL, NULL, 0, NULL}
401};
402
403static void test_dfp_ddedpd_ops(void)
404{
405   test_func_bcd_t func;
406   dfp_val_t test_val;
407
408   int k = 0;
409
410   while ((func = dfp_test_dfp_ddedpd_tests[k].test_func)) {
411      int i;
412      dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_ddedpd_tests[k];
413
414      for (i = 0; i < NUM_DFP_VALS; i++) {
415         unsigned int SP;
416
417         if (test_def.precision == LONG_TEST) {
418            test_val.u64_val = dfp64_vals[i];
419         } else {
420            test_val.u128.valu = dfp128_vals[i * 2];
421            test_val.u64_val = test_val.u128.valu;
422            test_val.u128.vall = dfp128_vals[(i * 2) + 1];
423         }
424
425         for (SP = 0; SP < 4; SP++) {
426            dfp_val_t result;
427            result = (*func)(SP, test_val);
428            printf("%s (SP=%d) %s%016llx", test_def.name, SP,
429                   test_def.op, test_val.u64_val);
430            if (test_def.precision == QUAD_TEST) {
431               printf(" %016llx", test_val.u128.vall);
432            }
433            if (test_def.precision == LONG_TEST)
434               printf(" ==> %016llx\n", result.u64_val);
435            else
436               printf(" ==> %016llx %016llx\n", result.u128.valu, result.u128.vall);
437         }
438      }
439      k++;
440      printf( "\n" );
441   }
442}
443
444static dfp_one_arg_bcd_test_t
445dfp_test_dfp_denbcd_tests[] = {
446                            { &_test_denbcd, "denbcd", LONG_TEST, "[B->D]"},
447                            { &_test_denbcdq, "denbcdq", QUAD_TEST, "[B->D]"},
448                            { NULL, NULL, 0, NULL}
449};
450
451static void test_dfp_denbcd_ops(void)
452{
453   test_func_bcd_t func;
454   dfp_val_t test_val;
455   int num_test_vals;
456
457   int k = 0;
458
459   while ((func = dfp_test_dfp_denbcd_tests[k].test_func)) {
460      int i;
461      dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_denbcd_tests[k];
462      if (test_def.precision == LONG_TEST)
463         num_test_vals = sizeof(bcd64_vals)/sizeof(unsigned long long);
464      else
465         num_test_vals = sizeof(bcd128_vals)/(2 * sizeof(unsigned long long));
466
467      for (i = 0; i < num_test_vals; i++) {
468         unsigned int S;
469         dfp_val_t result;
470         /* The DPD-to-BCD decodings may contain up to 3 decodings for each normal DFP
471          * value: the first is an unsigned decoding, and the other two are
472          * signed decodings, with SP[1] set to '0' and '1' respectively at decode
473          * time. But some of the results of decodings were duplicates, so they were
474          * not included in the bcd64_vals and bcd128_vals arrays.
475          *
476          * When doing the encoding operation (denbcd), we'll attempt both S=0 and
477          * S=1; one or the other should encode the BCD value to something close to
478          * its original DFP value (except being 2^4 in magnitude since the decoding
479          * operation shifted the value one hex digit to the left to make room
480          * for signedness info).
481          */
482         for (S = 0; S < 2; S++) {
483            if (test_def.precision == LONG_TEST) {
484               test_val.u64_val = bcd64_vals[i];
485            } else {
486               test_val.u128.valu = bcd128_vals[i * 2];
487               test_val.u64_val = test_val.u128.valu;
488               test_val.u128.vall = bcd128_vals[(i * 2) + 1];
489            }
490
491            result = (*func)(S, test_val);
492            printf("%s (S=%d) %s%016llx", test_def.name, S,
493                   test_def.op, test_val.u64_val);
494            if (test_def.precision == QUAD_TEST) {
495               printf(" %016llx", test_val.u128.vall);
496            }
497            if (test_def.precision == LONG_TEST)
498               printf(" ==> %016llx\n", result.u64_val);
499            else
500               printf(" ==> %016llx %016llx\n", result.u128.valu, result.u128.vall);
501         }
502      }
503      k++;
504      printf( "\n" );
505   }
506}
507
508
509static dfp_one_arg_test_t
510dfp_test_significance_tests[] = {
511                                          { &_test_dtstsf,  "dtstsf", LONG_TEST, "[tSig]"},
512                                          { &_test_dtstsfq, "dtstsfq", QUAD_TEST, "[tSig]"},
513                                          { NULL, NULL, 0, NULL}
514};
515
516static void test_dfp_test_significance_ops(void)
517{
518   test_func_t func;
519   dfp_val_t test_valB;
520   int k = 0;
521   unsigned int BF_vals[] = {BF_val1, BF_val2, BF_val3};
522   unsigned int reference_sig, reference_sig_vals[] = {0U, 1U, 2U, 4U, 6U, 63U};
523   int num_reference_sig_vals = sizeof(reference_sig_vals)/sizeof(unsigned int);
524
525   while ((func = dfp_test_significance_tests[k].test_func)) {
526      int i;
527      dfp_one_arg_test_t test_def = dfp_test_significance_tests[k];
528
529      for (i = 0; i < NUM_DFP_VALS; i++) {
530         int j;
531         if (test_def.precision == LONG_TEST) {
532            test_valB.u64_val = dfp64_vals[i];
533         } else {
534            test_valB.u128.valu = dfp128_vals[i * 2];
535            test_valB.u64_val = test_valB.u128.valu;
536            test_valB.u128.vall = dfp128_vals[(i * 2) + 1];
537         }
538
539         for (j = 0; j < num_reference_sig_vals; j++) {
540            int bf_idx, BF;
541            reference_sig = reference_sig_vals[j];
542            for (bf_idx = 0; bf_idx < sizeof(BF_vals)/sizeof(unsigned int); bf_idx++) {
543               unsigned int condreg;
544               unsigned int flags;
545               BF = BF_vals[bf_idx];
546               SET_FPSCR_ZERO;
547               SET_CR_XER_ZERO;
548               (*func)(BF, reference_sig, test_valB);
549               GET_CR(flags);
550
551               condreg = ((flags >> (4 * (7-BF)))) & 0xf;
552               printf("%s (ref_sig=%d) %s%016llx", test_def.name, reference_sig,
553                      test_def.op, test_valB.u64_val);
554               if (test_def.precision == QUAD_TEST) {
555                  printf(" %016llx", test_valB.u128.vall);
556               }
557               printf(" => %x (BF=%d)\n", condreg, BF);
558            }
559         }
560         printf( "\n" );
561      }
562      k++;
563   }
564}
565
566static test_table_t
567         all_tests[] =
568{
569                    { &test_dfp_test_significance_ops,
570                      "Test DFP test significance instructions"},
571                    { &test_dfp_ddedpd_ops,
572                      "Test DFP DPD-to-BCD instructions"},
573                    { &test_dfp_denbcd_ops,
574                      "Test DFP BCD-to-DPD instructions"},
575                    { NULL, NULL }
576};
577#endif // HAS_DFP
578
579int main() {
580#if defined(HAS_DFP)
581
582   test_table_t aTest;
583   test_driver_func_t func;
584   int i = 0;
585
586   while ((func = all_tests[i].test_category)) {
587      aTest = all_tests[i];
588      printf( "%s\n", aTest.name );
589      (*func)();
590      i++;
591   }
592
593#endif // HAS_DFP
594   return 0;
595}
596