drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / none / tests / ppc32 / test_dfp4.c
blobbce9130f709485ea3d5f04139e914ed51864f7b2
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) )
86 // The assembly-level instructions being tested
88 /* In _test_dtstdc[q], DCM can be one of 6 possible data classes, numbered 0-5.
89 * In reality, DCM is a 6-bit mask field. We just test the individual values
90 * and assume that masking multiple values would work OK.
91 * BF is the condition register bit field which can range from 0-7. But for
92 * testing purposes, we only use BF values of '0' and '5'.
94 static void _test_dtstdc(int BF, int DCM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
96 _Decimal64 f14 = val1->dec_val;
97 if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) {
98 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM);
99 return;
101 switch (DCM) {
102 case 0:
103 if (BF)
104 __asm__ __volatile__ ("dtstdc 5, %0, 1" : : "f" (f14));
105 else
106 __asm__ __volatile__ ("dtstdc 0, %0, 1" : : "f" (f14));
107 break;
108 case 1:
109 if (BF)
110 __asm__ __volatile__ ("dtstdc 5, %0, 2" : : "f" (f14));
111 else
112 __asm__ __volatile__ ("dtstdc 0, %0, 2" : : "f" (f14));
113 break;
114 case 2:
115 if (BF)
116 __asm__ __volatile__ ("dtstdc 5, %0, 4" : : "f" (f14));
117 else
118 __asm__ __volatile__ ("dtstdc 0, %0, 4" : : "f" (f14));
119 break;
120 case 3:
121 if (BF)
122 __asm__ __volatile__ ("dtstdc 5, %0, 8" : : "f" (f14));
123 else
124 __asm__ __volatile__ ("dtstdc 0, %0, 8" : : "f" (f14));
125 break;
126 case 4:
127 if (BF)
128 __asm__ __volatile__ ("dtstdc 5, %0, 16" : : "f" (f14));
129 else
130 __asm__ __volatile__ ("dtstdc 0, %0, 16" : : "f" (f14));
131 break;
132 case 5:
133 if (BF)
134 __asm__ __volatile__ ("dtstdc 5, %0, 32" : : "f" (f14));
135 else
136 __asm__ __volatile__ ("dtstdc 0, %0, 32" : : "f" (f14));
137 break;
138 default:
139 break;
143 static void _test_dtstdcq(int BF, int DCM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
145 _Decimal128 f14 = val1->dec_val128;
146 if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) {
147 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM);
148 return;
150 switch (DCM) {
151 case 0:
152 if (BF)
153 __asm__ __volatile__ ("dtstdcq 5, %0, 1" : : "f" (f14));
154 else
155 __asm__ __volatile__ ("dtstdcq 0, %0, 1" : : "f" (f14));
156 break;
157 case 1:
158 if (BF)
159 __asm__ __volatile__ ("dtstdcq 5, %0, 2" : : "f" (f14));
160 else
161 __asm__ __volatile__ ("dtstdcq 0, %0, 2" : : "f" (f14));
162 break;
163 case 2:
164 if (BF)
165 __asm__ __volatile__ ("dtstdcq 5, %0, 4" : : "f" (f14));
166 else
167 __asm__ __volatile__ ("dtstdcq 0, %0, 4" : : "f" (f14));
168 break;
169 case 3:
170 if (BF)
171 __asm__ __volatile__ ("dtstdcq 5, %0, 8" : : "f" (f14));
172 else
173 __asm__ __volatile__ ("dtstdcq 0, %0, 8" : : "f" (f14));
174 break;
175 case 4:
176 if (BF)
177 __asm__ __volatile__ ("dtstdcq 5, %0, 16" : : "f" (f14));
178 else
179 __asm__ __volatile__ ("dtstdcq 0, %0, 16" : : "f" (f14));
180 break;
181 case 5:
182 if (BF)
183 __asm__ __volatile__ ("dtstdcq 5, %0, 32" : : "f" (f14));
184 else
185 __asm__ __volatile__ ("dtstdcq 0, %0, 32" : : "f" (f14));
186 break;
187 default:
188 break;
192 /* In _test_dtstdg[q], DGM can be one of 6 possible data groups, numbered 0-5.
193 * In reality, DGM is a 6-bit mask field. We just test the individual values
194 * and assume that masking multiple values would work OK.
195 * BF is the condition register bit field which can range from 0-7. But for
196 * testing purposes, we only use BF values of '0' and '5'.
198 static void _test_dtstdg(int BF, int DGM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
200 _Decimal64 f14 = val1->dec_val;
201 if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) {
202 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM);
203 return;
205 switch (DGM) {
206 case 0:
207 if (BF)
208 __asm__ __volatile__ ("dtstdg 5, %0, 1" : : "f" (f14));
209 else
210 __asm__ __volatile__ ("dtstdg 0, %0, 1" : : "f" (f14));
211 break;
212 case 1:
213 if (BF)
214 __asm__ __volatile__ ("dtstdg 5, %0, 2" : : "f" (f14));
215 else
216 __asm__ __volatile__ ("dtstdg 0, %0, 2" : : "f" (f14));
217 break;
218 case 2:
219 if (BF)
220 __asm__ __volatile__ ("dtstdg 5, %0, 4" : : "f" (f14));
221 else
222 __asm__ __volatile__ ("dtstdg 0, %0, 4" : : "f" (f14));
223 break;
224 case 3:
225 if (BF)
226 __asm__ __volatile__ ("dtstdg 5, %0, 8" : : "f" (f14));
227 else
228 __asm__ __volatile__ ("dtstdg 0, %0, 8" : : "f" (f14));
229 break;
230 case 4:
231 if (BF)
232 __asm__ __volatile__ ("dtstdg 5, %0, 16" : : "f" (f14));
233 else
234 __asm__ __volatile__ ("dtstdg 0, %0, 16" : : "f" (f14));
235 break;
236 case 5:
237 if (BF)
238 __asm__ __volatile__ ("dtstdg 5, %0, 32" : : "f" (f14));
239 else
240 __asm__ __volatile__ ("dtstdg 0, %0, 32" : : "f" (f14));
241 break;
242 default:
243 break;
247 static void _test_dtstdgq(int BF, int DGM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
249 _Decimal128 f14 = val1->dec_val128;
250 if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) {
251 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM);
252 return;
254 switch (DGM) {
255 case 0:
256 if (BF)
257 __asm__ __volatile__ ("dtstdgq 5, %0, 1" : : "f" (f14));
258 else
259 __asm__ __volatile__ ("dtstdgq 0, %0, 1" : : "f" (f14));
260 break;
261 case 1:
262 if (BF)
263 __asm__ __volatile__ ("dtstdgq 5, %0, 2" : : "f" (f14));
264 else
265 __asm__ __volatile__ ("dtstdgq 0, %0, 2" : : "f" (f14));
266 break;
267 case 2:
268 if (BF)
269 __asm__ __volatile__ ("dtstdgq 5, %0, 4" : : "f" (f14));
270 else
271 __asm__ __volatile__ ("dtstdgq 0, %0, 4" : : "f" (f14));
272 break;
273 case 3:
274 if (BF)
275 __asm__ __volatile__ ("dtstdgq 5, %0, 8" : : "f" (f14));
276 else
277 __asm__ __volatile__ ("dtstdgq 0, %0, 8" : : "f" (f14));
278 break;
279 case 4:
280 if (BF)
281 __asm__ __volatile__ ("dtstdgq 5, %0, 16" : : "f" (f14));
282 else
283 __asm__ __volatile__ ("dtstdgq 0, %0, 16" : : "f" (f14));
284 break;
285 case 5:
286 if (BF)
287 __asm__ __volatile__ ("dtstdgq 5, %0, 32" : : "f" (f14));
288 else
289 __asm__ __volatile__ ("dtstdgq 0, %0, 32" : : "f" (f14));
290 break;
291 default:
292 break;
296 /* In _test_dtstex[q], BF is the condition register bit field indicating the
297 * CR field in which the result of the test should be placed. BF can range
298 * from 0-7, but for testing purposes, we only use BF values of '4' and '7'.
300 static void
301 _test_dtstex(int BF, int x __attribute__((unused)), dfp_val_t *val1, dfp_val_t *val2)
303 _Decimal64 f14 = val1->dec_val;
304 _Decimal64 f16 = val2->dec_val;
305 if (!(BF == 4 || BF == 7)) {
306 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF);
307 return;
309 switch (BF) {
310 case 4:
311 __asm__ __volatile__ ("dtstex 4, %0, %1" : : "f" (f14),"f" (f16));
312 break;
313 case 7:
314 __asm__ __volatile__ ("dtstex 7, %0, %1" : : "f" (f14),"f" (f16));
315 break;
316 default:
317 break;
321 static void _test_dtstexq(int BF, int x __attribute__((unused)), dfp_val_t *val1, dfp_val_t *val2)
323 _Decimal128 f14 = val1->dec_val128;
324 _Decimal128 f16 = val2->dec_val128;
325 if (!(BF == 4 || BF == 7)) {
326 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF);
327 return;
329 switch (BF) {
330 case 4:
331 __asm__ __volatile__ ("dtstexq 4, %0, %1" : : "f" (f14),"f" (f16));
332 break;
333 case 7:
334 __asm__ __volatile__ ("dtstexq 7, %0, %1" : : "f" (f14),"f" (f16));
335 break;
336 default:
337 break;
343 typedef void (*test_funcp_t)(int a, int b, dfp_val_t *val1, dfp_val_t *val2);
344 typedef void (*test_driver_func_t)(void);
345 typedef struct test_table
347 test_driver_func_t test_category;
348 char * name;
349 } test_table_t;
352 * 345.0DD (0x2207c00000000000 0xe50)
353 * 1.2300e+5DD (0x2207c00000000000 0x14c000)
354 * -16.0DD (0xa207c00000000000 0xe0)
355 * 0.00189DD (0x2206c00000000000 0xcf)
356 * -4.1235DD (0xa205c00000000000 0x10a395bcf)
357 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
358 * 0DD (0x2208000000000000 0x0)
359 * 0DD (0x2208000000000000 0x0)
360 * infDD (0x7800000000000000 0x0)
361 * nanDD (0x7c00000000000000 0x0
363 static unsigned long long dfp128_vals[] = {
364 // Some finite numbers
365 0x2207c00000000000ULL, 0x0000000000000e50ULL,
366 0x2207c00000000000ULL, 0x000000000014c000ULL,
367 0xa207c00000000000ULL, 0x00000000000000e0ULL,
368 0x2206c00000000000ULL, 0x00000000000000cfULL,
369 0xa205c00000000000ULL, 0x000000010a395bcfULL,
370 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
371 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
372 // flavors of zero
373 0x2208000000000000ULL, 0x0000000000000000ULL,
374 0xa208000000000000ULL, 0x0000000000000000ULL, // negative
375 0xa248000000000000ULL, 0x0000000000000000ULL,
376 // flavors of NAN
377 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
378 0xfc00000000000000ULL, 0xc00100035b007700ULL,
379 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
380 // flavors of Infinity
381 0x7800000000000000ULL, 0x0000000000000000ULL,
382 0xf800000000000000ULL, 0x0000000000000000ULL, // negative
383 0xf900000000000000ULL, 0x0000000000000000ULL
386 static unsigned long long dfp64_vals[] = {
387 // various finite numbers
388 0x2234000000000e50ULL,
389 0x223400000014c000ULL,
390 0xa2340000000000e0ULL,// negative
391 0x22240000000000cfULL,
392 0xa21400010a395bcfULL,// negative
393 0x6e4d3f1f534acdd4ULL,// huge number
394 0x000400000089b000ULL,// very small number
395 // flavors of zero
396 0x2238000000000000ULL,
397 0xa238000000000000ULL,
398 0x4248000000000000ULL,
399 // flavors of NAN
400 0x7e34000000000111ULL,
401 0xfe000000d0e0a0d0ULL,//signaling
402 0xfc00000000000000ULL,//quiet
403 // flavors of Infinity
404 0x7800000000000000ULL,
405 0xf800000000000000ULL,//negative
406 0x7a34000000000000ULL,
409 // Both Long and Quad arrays of DFP values should have the same length, so it
410 // doesn't matter which array I use for calculating the following #define.
411 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8)
413 typedef struct dfp_test_args {
414 int fra_idx;
415 int frb_idx;
416 } dfp_test_args_t;
419 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests
420 static dfp_test_args_t dfp_2args_x1[] = {
421 {0, 1},
422 {2, 1},
423 {4, 3},
424 {6, 0},
425 {2, 4},
426 {5, 1},
427 {5, 2},
428 {7, 1},
429 {7, 2},
430 {8, 0},
431 {8, 1},
432 {8, 2},
433 {7, 8},
434 {12, 14},
435 {12, 1},
436 {12, 13},
437 {12, 12},
438 {12, 11},
439 {11, 14},
440 {11, 0},
441 {11, 13},
442 {11, 11},
443 {14, 14},
444 {14, 3},
445 {14, 15},
448 typedef enum {
449 LONG_TEST,
450 QUAD_TEST
451 } precision_type_t;
453 typedef struct dfp_test
455 test_funcp_t test_func;
456 const char * name;
457 dfp_test_args_t * targs;
458 int num_tests;
459 precision_type_t precision;
460 const char * op;
461 } dfp_test_t;
463 typedef struct dfp_one_arg_test
465 test_funcp_t test_func;
466 const char * name;
467 precision_type_t precision;
468 const char * op;
469 } dfp_one_arg_test_t;
473 static dfp_one_arg_test_t
474 dfp_ClassAndGroupTest_tests[] = {
475 { &_test_dtstdc, "dtstdc", LONG_TEST, "[tCls]"},
476 { &_test_dtstdcq, "dtstdcq", QUAD_TEST, "[tCls]"},
477 { &_test_dtstdg, "dtstdg", LONG_TEST, "[tGrp]"},
478 { &_test_dtstdgq, "dtstdgq", QUAD_TEST, "[tGrp]"},
479 { NULL, NULL, 0, NULL}
482 static void test_dfp_ClassAndGroupTest_ops(void)
484 test_funcp_t func;
485 dfp_val_t test_val, dummy;
487 int k = 0;
489 while ((func = dfp_ClassAndGroupTest_tests[k].test_func)) {
490 int i;
491 dfp_one_arg_test_t test_def = dfp_ClassAndGroupTest_tests[k];
493 for (i = 0; i < NUM_DFP_VALS; i++) {
494 int data_class_OR_group, BF = 0;
495 Bool repeat = True;
497 if (test_def.precision == LONG_TEST) {
498 test_val.u64_val = dfp64_vals[i];
499 } else {
500 test_val.u128.valu = dfp128_vals[i * 2];
501 test_val.u128.vall = dfp128_vals[(i * 2) + 1];
504 again:
505 for (data_class_OR_group = 0; data_class_OR_group < 6; data_class_OR_group++) {
506 unsigned int condreg;
507 unsigned int flags;
508 SET_FPSCR_ZERO;
509 SET_CR_XER_ZERO;
511 /* There is an ABI change in how 128 bit arguments are aligned
512 * with GCC 5.0. The compiler generates a "note" about this
513 * starting with GCC 4.8. To avoid generating the "note", pass
514 * the address of the 128-bit arguments rather then the value.
516 (*func)(BF, data_class_OR_group, &test_val, &dummy);
517 GET_CR(flags);
519 condreg = ((flags >> (4 * (7-BF)))) & 0xf;
520 printf("%s (DC/DG=%d) %s", test_def.name, data_class_OR_group,
521 test_def.op);
522 if (test_def.precision == QUAD_TEST) {
523 printf("%016llx %016llx", test_val.u128.valu, test_val.u128.vall);
524 } else {
525 printf("%016llx", test_val.u64_val);
528 //%016llx
529 printf(" => %x (BF=%d)\n", condreg, BF);
531 if (repeat) {
532 repeat = False;
533 BF = 5;
534 goto again;
537 k++;
538 printf( "\n" );
543 static dfp_test_t
544 dfp_ExpTest_tests[] = {
545 { &_test_dtstex, "dtstex", dfp_2args_x1, 25, LONG_TEST, "[tExp]"},
546 { &_test_dtstexq, "dtstexq", dfp_2args_x1, 25, QUAD_TEST, "[tExp]"},
547 { NULL, NULL, NULL, 0, 0, NULL}
551 static void test_dfp_ExpTest_ops(void)
553 dfp_val_t test_val1, test_val2;
554 test_funcp_t func;
555 int k = 0;
557 while ((func = dfp_ExpTest_tests[k].test_func)) {
558 /* BF is a 3-bit instruction field that indicates the CR field in which the
559 * result of the test should be placed. We won't iterate through all
560 * 8 possible BF values since storing compare results to a given field is
561 * a well-tested mechanism in VEX. But we will test two BF values, just as
562 * a sniff-test.
564 int i, repeat = 1, BF = 4;
565 dfp_test_t test_def = dfp_ExpTest_tests[k];
567 again:
568 for (i = 0; i < test_def.num_tests; i++) {
569 unsigned int condreg;
570 unsigned int flags;
572 if (test_def.precision == LONG_TEST) {
573 test_val1.u64_val = dfp64_vals[test_def.targs[i].fra_idx];
574 test_val2.u64_val = dfp64_vals[test_def.targs[i].frb_idx];
575 } else {
576 test_val1.u128.valu = dfp128_vals[test_def.targs[i].fra_idx * 2];
577 test_val1.u128.vall = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1];
578 test_val2.u128.valu = dfp128_vals[test_def.targs[i].frb_idx * 2];
579 test_val2.u128.vall = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1];
582 SET_FPSCR_ZERO;
583 SET_CR_XER_ZERO;
584 /* There is an ABI change in how 128 bit arguments are aligned
585 * with GCC 5.0. The compiler generates a "note" about this
586 * starting with GCC 4.8. To avoid generating the "note", pass
587 * the address of the 128-bit arguments rather then the value.
589 (*func)(BF, 0, &test_val1, &test_val2);
590 GET_CR(flags);
592 condreg = ((flags >> (4 * (7-BF)))) & 0xf;
593 printf("%s ", test_def.name);
594 if (test_def.precision == LONG_TEST) {
595 printf("%016llx %s %016llx ",
596 test_val1.u64_val, test_def.op, test_val2.u64_val);
597 } else {
598 printf("%016llx %016llx %s %016llx %016llx ",
599 test_val1.u128.valu, test_val1.u128.vall, test_def.op, test_val2.u128.valu, test_val2.u128.vall);
601 printf(" => %x (BF=%d)\n", condreg, BF);
603 if (repeat) {
604 repeat = 0;
605 BF = 7;
606 goto again;
608 k++;
609 printf( "\n" );
614 static test_table_t
615 all_tests[] =
617 { &test_dfp_ExpTest_ops,
618 "Test DFP exponent test instructions"},
619 { &test_dfp_ClassAndGroupTest_ops,
620 "Test DFP class and group test instructions"},
621 { NULL, NULL }
623 #endif // HAS_DFP
625 int main() {
626 #if defined(HAS_DFP)
628 test_table_t aTest;
629 test_driver_func_t func;
630 int i = 0;
632 while ((func = all_tests[i].test_category)) {
633 aTest = all_tests[i];
634 printf( "%s\n", aTest.name );
635 (*func)();
636 i++;
639 #endif // HAS_DFP
640 return 0;