drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / none / tests / ppc32 / test_dfp5.c
blob9af94b81f98113db0553588da263a4f707c3c573
1 /* Copyright (C) 2012 IBM
3 Author: Maynard Johnson <maynardj@us.ibm.com>
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
18 The GNU General Public License is contained in the file COPYING.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
25 #if defined(HAS_DFP)
27 typedef union stuff {
28 _Decimal64 dec_val;
29 _Decimal128 dec_val128;
30 unsigned long long u64_val;
31 struct {
32 #if defined(VGP_ppc64le_linux)
33 unsigned long long vall;
34 unsigned long long valu;
35 #else
36 unsigned long long valu;
37 unsigned long long vall;
38 #endif
39 } u128;
40 } dfp_val_t;
43 typedef unsigned char Bool;
44 #define True 1
45 #define False 0
48 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
50 #define SET_CR(_arg) \
51 __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
53 #define SET_XER(_arg) \
54 __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
56 #define GET_CR(_lval) \
57 __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) )
59 #define GET_XER(_lval) \
60 __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
62 #define GET_CR_XER(_lval_cr,_lval_xer) \
63 do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0)
65 #define SET_CR_ZERO \
66 SET_CR(0)
68 #define SET_XER_ZERO \
69 SET_XER(0)
71 #define SET_CR_XER_ZERO \
72 do { SET_CR_ZERO; SET_XER_ZERO; } while (0)
74 #define SET_FPSCR_ZERO \
75 do { double _d = 0.0; \
76 __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
77 } while (0)
79 #define GET_FPSCR(_arg) \
80 __asm__ __volatile__ ("mffs %0" : "=f"(_arg) )
82 #define SET_FPSCR_DRN \
83 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) )
85 #ifndef __powerpc64__
86 typedef uint32_t HWord_t;
87 #else
88 typedef uint64_t HWord_t;
89 #endif /* __powerpc64__ */
91 enum BF_vals { BF_val1 = 0, BF_val2 = 1, BF_val3 =6};
93 // The assembly-level instructions being tested
94 static void _test_dtstsf(unsigned int BF, unsigned int ref_sig, dfp_val_t *valB)
96 _Decimal64 f16 = valB->dec_val;
97 register HWord_t r14 __asm__ ("r14");
98 double f14;
99 r14 = (HWord_t)&ref_sig;
101 __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14));
102 switch (BF) {
103 case BF_val1:
104 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16));
105 break;
106 case BF_val2:
107 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16));
108 break;
109 case BF_val3:
110 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16));
111 break;
112 default:
113 fprintf(stderr, "Invalid value %d for BF\n", BF);
114 break;
118 static void _test_dtstsfq(unsigned int BF, unsigned int ref_sig, dfp_val_t *valB)
120 _Decimal128 f16 = valB->dec_val128;
121 register HWord_t r14 __asm__ ("r14");
122 double f14;
123 r14 = (HWord_t)&ref_sig;
125 __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14));
126 switch (BF) {
127 case BF_val1:
128 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16));
129 break;
130 case BF_val2:
131 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16));
132 break;
133 case BF_val3:
134 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16));
135 break;
136 default:
137 fprintf(stderr, "Invalid value %d for BF\n", BF);
138 break;
142 static dfp_val_t _test_ddedpd(unsigned int SP, dfp_val_t *valB)
144 _Decimal64 ret = 0;
145 dfp_val_t result;
146 _Decimal64 f16 = valB->dec_val;
147 switch (SP) {
148 case 0:
149 __asm__ __volatile__ ("ddedpd. 0, %0, %1" : "=f" (ret) : "f" (f16));
150 break;
151 case 1:
152 __asm__ __volatile__ ("ddedpd. 1, %0, %1" : "=f" (ret) : "f" (f16));
153 break;
154 case 2:
155 __asm__ __volatile__ ("ddedpd. 2, %0, %1" : "=f" (ret) : "f" (f16));
156 break;
157 case 3:
158 __asm__ __volatile__ ("ddedpd. 3, %0, %1" : "=f" (ret) : "f" (f16));
159 break;
160 default:
161 fprintf(stderr, "Invalid value %d for SP\n", SP);
162 break;
164 result.dec_val = ret;
165 return result;
169 static dfp_val_t _test_ddedpdq(unsigned int SP, dfp_val_t *valB)
171 _Decimal128 ret = 0;
172 dfp_val_t result;
173 _Decimal128 f16 = valB->dec_val128;
174 switch (SP) {
175 case 0:
176 __asm__ __volatile__ ("ddedpdq 0, %0, %1" : "=f" (ret) : "f" (f16));
177 break;
178 case 1:
179 __asm__ __volatile__ ("ddedpdq 1, %0, %1" : "=f" (ret) : "f" (f16));
180 break;
181 case 2:
182 __asm__ __volatile__ ("ddedpdq 2, %0, %1" : "=f" (ret) : "f" (f16));
183 break;
184 case 3:
185 __asm__ __volatile__ ("ddedpdq 3, %0, %1" : "=f" (ret) : "f" (f16));
186 break;
187 default:
188 fprintf(stderr, "Invalid value %d for SP\n", SP);
189 break;
191 result.dec_val128 = ret;
192 return result;
195 static dfp_val_t _test_denbcd(unsigned int S, dfp_val_t *valB)
197 _Decimal64 ret = 0;
198 dfp_val_t result;
199 _Decimal64 f16 = valB->dec_val;
200 switch (S) {
201 case 0:
202 __asm__ __volatile__ ("denbcd. 0, %0, %1" : "=f" (ret) : "f" (f16));
203 break;
204 case 1:
205 __asm__ __volatile__ ("denbcd. 1, %0, %1" : "=f" (ret) : "f" (f16));
206 break;
207 default:
208 fprintf(stderr, "Invalid value %d for S\n", S);
209 break;
211 result.dec_val = ret;
212 return result;
216 static dfp_val_t _test_denbcdq(unsigned int S, dfp_val_t *valB)
218 _Decimal128 ret = 0;
219 dfp_val_t result;
220 _Decimal128 f16 = valB->dec_val128;
221 switch (S) {
222 case 0:
223 __asm__ __volatile__ ("denbcdq 0, %0, %1" : "=f" (ret) : "f" (f16));
224 break;
225 case 1:
226 __asm__ __volatile__ ("denbcdq 1, %0, %1" : "=f" (ret) : "f" (f16));
227 break;
228 default:
229 fprintf(stderr, "Invalid value %d for S\n", S);
230 break;
232 result.dec_val128 = ret;
233 return result;
237 typedef void (*test_funcp_t)(unsigned int imm, unsigned int imm2, dfp_val_t *valB);
238 typedef dfp_val_t (*test_func_bcdp_t)(unsigned int imm, dfp_val_t *valB);
239 typedef void (*test_driver_func_t)(void);
240 typedef struct test_table
242 test_driver_func_t test_category;
243 char * name;
244 } test_table_t;
247 * 345.0DD (0x2207c00000000000 0xe50)
248 * 1.2300e+5DD (0x2207c00000000000 0x14c000)
249 * -16.0DD (0xa207c00000000000 0xe0)
250 * 0.00189DD (0x2206c00000000000 0xcf)
251 * -4.1235DD (0xa205c00000000000 0x10a395bcf)
252 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
253 * 0DD (0x2208000000000000 0x0)
254 * 0DD (0x2208000000000000 0x0)
255 * infDD (0x7800000000000000 0x0)
256 * nanDD (0x7c00000000000000 0x0
258 static unsigned long long dfp128_vals[] = {
259 // Some finite numbers
260 0x2207c00000000000ULL, 0x0000000000000e50ULL,
261 0x2207c00000000000ULL, 0x000000000014c000ULL,
262 0xa207c00000000000ULL, 0x00000000000000e0ULL,
263 0x2206c00000000000ULL, 0x00000000000000cfULL,
264 0xa205c00000000000ULL, 0x000000010a395bcfULL,
265 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
266 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
267 // flavors of zero
268 0x2208000000000000ULL, 0x0000000000000000ULL,
269 0xa208000000000000ULL, 0x0000000000000000ULL, // negative
270 0xa248000000000000ULL, 0x0000000000000000ULL,
271 // flavors of NAN
272 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
273 0xfc00000000000000ULL, 0xc00100035b007700ULL,
274 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
275 // flavors of Infinity
276 0x7800000000000000ULL, 0x0000000000000000ULL,
277 0xf800000000000000ULL, 0x0000000000000000ULL, // negative
278 0xf900000000000000ULL, 0x0000000000000000ULL
281 static unsigned long long dfp64_vals[] = {
282 // various finite numbers
283 0x2234000000000e50ULL,
284 0x223400000014c000ULL,
285 0xa2340000000000e0ULL,// negative
286 0x22240000000000cfULL,
287 0xa21400010a395bcfULL,// negative
288 0x6e4d3f1f534acdd4ULL,// huge number
289 0x000400000089b000ULL,// very small number
290 // flavors of zero
291 0x2238000000000000ULL,
292 0xa238000000000000ULL,
293 0x4248000000000000ULL,
294 // flavors of NAN
295 0x7e34000000000111ULL,
296 0xfe000000d0e0a0d0ULL,//signaling
297 0xfc00000000000000ULL,//quiet
298 // flavors of Infinity
299 0x7800000000000000ULL,
300 0xf800000000000000ULL,//negative
301 0x7a34000000000000ULL,
304 /* The bcd64_vals and bdc128_vals hold the unique results of executing
305 * the ddedpd instruction on the basic dfp64 and dfp128 array values.
306 * Executing the inverse operation (denbcd) on these values with the
307 * appropriate S (signed) value should yield values approximating the
308 * original dfp values (except being 2^4 in magnitude since the decoding
309 * operation shifted the value one hex digit to the left to make room
310 * for signedness info).
312 static unsigned long long bcd64_vals[] = {
313 0x0000000000003450ULL,
314 0x000000000003450cULL,
315 0x000000000003450fULL,
316 0x0000000001230000ULL,
317 0x000000001230000cULL,
318 0x000000001230000fULL,
319 0x0000000000000160ULL,
320 0x000000000000160dULL,
321 0x0000000000000189ULL,
322 0x000000000000189cULL,
323 0x000000000000189fULL,
324 0x0000004123456789ULL,
325 0x000004123456789dULL,
326 0x9839871234533354ULL,
327 0x839871234533354cULL,
328 0x839871234533354fULL,
329 0x0000000008864000ULL,
330 0x000000008864000cULL,
331 0x000000008864000fULL,
332 0x0000000000000000ULL,
333 0x000000000000000cULL,
334 0x000000000000000fULL,
335 0x000000000000000dULL,
336 0x0000000000000211ULL,
337 0x000000000000211cULL,
338 0x000000000000211fULL,
339 0x0000003882028150ULL,
340 0x000003882028150dULL
343 static unsigned long long bcd128_vals[] = {
344 0x0000000000000000ULL, 0x0000000000003450ULL,
345 0x0000000000000000ULL, 0x000000000003450cULL,
346 0x0000000000000000ULL, 0x000000000003450fULL,
347 0x0000000000000000ULL, 0x0000000001230000ULL,
348 0x0000000000000000ULL, 0x000000001230000cULL,
349 0x0000000000000000ULL, 0x000000001230000fULL,
350 0x0000000000000000ULL, 0x0000000000000160ULL,
351 0x0000000000000000ULL, 0x000000000000160dULL,
352 0x0000000000000000ULL, 0x0000000000000189ULL,
353 0x0000000000000000ULL, 0x000000000000189cULL,
354 0x0000000000000000ULL, 0x000000000000189fULL,
355 0x0000000000000000ULL, 0x0000004123456789ULL,
356 0x0000000000000000ULL, 0x000004123456789dULL,
357 0x0000097100000000ULL, 0x9839871234533354ULL,
358 0x0000971000000009ULL, 0x839871234533354cULL,
359 0x0000971000000009ULL, 0x839871234533354fULL,
360 0x0000010954000051ULL, 0x8000640000000049ULL,
361 0x0000109540000518ULL, 0x000640000000049cULL,
362 0x0000109540000518ULL, 0x000640000000049fULL,
363 0x0000000000000000ULL, 0x0000000000000000ULL,
364 0x0000000000000000ULL, 0x000000000000000cULL,
365 0x0000000000000000ULL, 0x000000000000000fULL,
366 0x0000000000000000ULL, 0x000000000000000dULL,
367 0x0000000000080000ULL, 0x0200801330811600ULL,
368 0x0000000000800000ULL, 0x200801330811600dULL,
369 0x0000000000088170ULL, 0x0000003882028150ULL,
370 0x0000000000881700ULL, 0x000003882028150cULL,
371 0x0000000000881700ULL, 0x000003882028150fULL
374 // Both Long and Quad arrays of DFP values should have the same length, so it
375 // doesn't matter which array I use for calculating the following #define.
376 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8)
378 typedef enum {
379 LONG_TEST,
380 QUAD_TEST
381 } precision_type_t;
383 typedef struct dfp_one_arg_test
385 test_funcp_t test_func;
386 const char * name;
387 precision_type_t precision;
388 const char * op;
389 } dfp_one_arg_test_t;
391 typedef struct dfp_one_arg_bcd_test
393 test_func_bcdp_t test_func;
394 const char * name;
395 precision_type_t precision;
396 const char * op;
397 } dfp_one_arg_bcd_test_t;
399 static dfp_one_arg_bcd_test_t
400 dfp_test_dfp_ddedpd_tests[] = {
401 { &_test_ddedpd, "ddedpd", LONG_TEST, "[D->B]"},
402 { &_test_ddedpdq, "ddedpdq", QUAD_TEST, "[D->B]"},
403 { NULL, NULL, 0, NULL}
406 static void test_dfp_ddedpd_ops(void)
408 test_func_bcdp_t func;
409 dfp_val_t test_val;
411 int k = 0;
413 while ((func = dfp_test_dfp_ddedpd_tests[k].test_func)) {
414 int i;
415 dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_ddedpd_tests[k];
417 for (i = 0; i < NUM_DFP_VALS; i++) {
418 unsigned int SP;
420 if (test_def.precision == LONG_TEST) {
421 test_val.u64_val = dfp64_vals[i];
422 } else {
423 test_val.u128.valu = dfp128_vals[i * 2];
424 test_val.u128.vall = dfp128_vals[(i * 2) + 1];
427 for (SP = 0; SP < 4; SP++) {
428 dfp_val_t result;
430 /* There is an ABI change in how 128 bit arguments are aligned
431 * with GCC 5.0. The compiler generates a "note" about this
432 * starting with GCC 4.8. To avoid generating the "note", pass
433 * the address of the 128-bit arguments rather then the value.
435 result = (*func)(SP, &test_val);
436 printf("%s (SP=%d) %s", test_def.name, SP, test_def.op);
437 if (test_def.precision == LONG_TEST) {
438 printf("%016llx ==> %016llx\n", test_val.u64_val, result.u64_val);
439 } else {
440 printf("%016llx %016llx ==> %016llx %016llx\n",
441 test_val.u128.valu, test_val.u128.vall,
442 result.u128.valu, result.u128.vall);
446 k++;
447 printf( "\n" );
451 static dfp_one_arg_bcd_test_t
452 dfp_test_dfp_denbcd_tests[] = {
453 { &_test_denbcd, "denbcd", LONG_TEST, "[B->D]"},
454 { &_test_denbcdq, "denbcdq", QUAD_TEST, "[B->D]"},
455 { NULL, NULL, 0, NULL}
458 static void test_dfp_denbcd_ops(void)
460 test_func_bcdp_t func;
461 dfp_val_t test_val;
462 int num_test_vals;
464 int k = 0;
466 while ((func = dfp_test_dfp_denbcd_tests[k].test_func)) {
467 int i;
468 dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_denbcd_tests[k];
469 if (test_def.precision == LONG_TEST)
470 num_test_vals = sizeof(bcd64_vals)/sizeof(unsigned long long);
471 else
472 num_test_vals = sizeof(bcd128_vals)/(2 * sizeof(unsigned long long));
474 for (i = 0; i < num_test_vals; i++) {
475 unsigned int S;
476 dfp_val_t result;
477 /* The DPD-to-BCD decodings may contain up to 3 decodings for each normal DFP
478 * value: the first is an unsigned decoding, and the other two are
479 * signed decodings, with SP[1] set to '0' and '1' respectively at decode
480 * time. But some of the results of decodings were duplicates, so they were
481 * not included in the bcd64_vals and bcd128_vals arrays.
483 * When doing the encoding operation (denbcd), we'll attempt both S=0 and
484 * S=1; one or the other should encode the BCD value to something close to
485 * its original DFP value (except being 2^4 in magnitude since the decoding
486 * operation shifted the value one hex digit to the left to make room
487 * for signedness info).
489 for (S = 0; S < 2; S++) {
490 if (test_def.precision == LONG_TEST) {
491 test_val.u64_val = bcd64_vals[i];
492 } else {
493 test_val.u128.valu = bcd128_vals[i * 2];
494 test_val.u128.vall = bcd128_vals[(i * 2) + 1];
497 /* There is an API change in how 128 bit arguments are aligned
498 * with GCC 5.0. The compiler generates a "note" about this
499 * starting with GCC 4.8. To avoid generating the "note", pass
500 * the address of the 128-bit arguments rather then the value.
502 result = (*func)(S, &test_val);
503 printf("%s (S=%d) %s", test_def.name, S, test_def.op);
504 if (test_def.precision == LONG_TEST) {
505 printf("%016llx ==> %016llx\n", test_val.u64_val, result.u64_val);
506 } else {
507 printf("%016llx %016llx ==> %016llx %016llx\n",
508 test_val.u128.valu, test_val.u128.vall,
509 result.u128.valu, result.u128.vall);
513 k++;
514 printf( "\n" );
519 static dfp_one_arg_test_t
520 dfp_test_significance_tests[] = {
521 { &_test_dtstsf, "dtstsf", LONG_TEST, "[tSig]"},
522 { &_test_dtstsfq, "dtstsfq", QUAD_TEST, "[tSig]"},
523 { NULL, NULL, 0, NULL}
526 static void test_dfp_test_significance_ops(void)
528 test_funcp_t func;
529 dfp_val_t test_valB;
530 int k = 0;
531 unsigned int BF_vals[] = {BF_val1, BF_val2, BF_val3};
532 unsigned int reference_sig, reference_sig_vals[] = {0U, 1U, 2U, 4U, 6U, 63U};
533 int num_reference_sig_vals = sizeof(reference_sig_vals)/sizeof(unsigned int);
535 while ((func = dfp_test_significance_tests[k].test_func)) {
536 int i;
537 dfp_one_arg_test_t test_def = dfp_test_significance_tests[k];
539 for (i = 0; i < NUM_DFP_VALS; i++) {
540 int j;
541 if (test_def.precision == LONG_TEST) {
542 test_valB.u64_val = dfp64_vals[i];
543 } else {
544 test_valB.u128.valu = dfp128_vals[i * 2];
545 test_valB.u128.vall = dfp128_vals[(i * 2) + 1];
548 for (j = 0; j < num_reference_sig_vals; j++) {
549 int bf_idx, BF;
550 reference_sig = reference_sig_vals[j];
551 for (bf_idx = 0; bf_idx < sizeof(BF_vals)/sizeof(unsigned int); bf_idx++) {
552 unsigned int condreg;
553 unsigned int flags;
554 BF = BF_vals[bf_idx];
555 SET_FPSCR_ZERO;
556 SET_CR_XER_ZERO;
557 /* There is an ABI change in how 128 bit arguments are aligned
558 * with GCC 5.0. The compiler generates a "note" about this
559 * starting with GCC 4.9. To avoid generating the "note", pass
560 * the address of the 128-bit arguments rather then the value.
562 (*func)(BF, reference_sig, &test_valB);
563 GET_CR(flags);
565 condreg = ((flags >> (4 * (7-BF)))) & 0xf;
566 printf("%s (ref_sig=%d) %s", test_def.name, reference_sig, test_def.op);
567 if (test_def.precision == LONG_TEST) {
568 printf("%016llx", test_valB.u64_val);
569 } else {
570 printf("%016llx %016llx", test_valB.u128.valu, test_valB.u128.vall);
572 printf(" => %x (BF=%d)\n", condreg, BF);
575 printf( "\n" );
577 k++;
581 static test_table_t
582 all_tests[] =
584 { &test_dfp_test_significance_ops,
585 "Test DFP test significance instructions"},
586 { &test_dfp_ddedpd_ops,
587 "Test DFP DPD-to-BCD instructions"},
588 { &test_dfp_denbcd_ops,
589 "Test DFP BCD-to-DPD instructions"},
590 { NULL, NULL }
592 #endif // HAS_DFP
594 int main() {
595 #if defined(HAS_DFP)
597 test_table_t aTest;
598 test_driver_func_t func;
599 int i = 0;
601 while ((func = all_tests[i].test_category)) {
602 aTest = all_tests[i];
603 printf( "%s\n", aTest.name );
604 (*func)();
605 i++;
608 #endif // HAS_DFP
609 return 0;