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.
29 _Decimal128 dec_val128
;
30 unsigned long long u64_val
;
32 #if defined(VGP_ppc64le_linux)
33 unsigned long long vall
;
34 unsigned long long valu
;
36 unsigned long long valu
;
37 unsigned long long vall
;
43 typedef unsigned char Bool
;
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)
68 #define SET_XER_ZERO \
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) ); \
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
);
104 __asm__
__volatile__ ("dtstdc 5, %0, 1" : : "f" (f14
));
106 __asm__
__volatile__ ("dtstdc 0, %0, 1" : : "f" (f14
));
110 __asm__
__volatile__ ("dtstdc 5, %0, 2" : : "f" (f14
));
112 __asm__
__volatile__ ("dtstdc 0, %0, 2" : : "f" (f14
));
116 __asm__
__volatile__ ("dtstdc 5, %0, 4" : : "f" (f14
));
118 __asm__
__volatile__ ("dtstdc 0, %0, 4" : : "f" (f14
));
122 __asm__
__volatile__ ("dtstdc 5, %0, 8" : : "f" (f14
));
124 __asm__
__volatile__ ("dtstdc 0, %0, 8" : : "f" (f14
));
128 __asm__
__volatile__ ("dtstdc 5, %0, 16" : : "f" (f14
));
130 __asm__
__volatile__ ("dtstdc 0, %0, 16" : : "f" (f14
));
134 __asm__
__volatile__ ("dtstdc 5, %0, 32" : : "f" (f14
));
136 __asm__
__volatile__ ("dtstdc 0, %0, 32" : : "f" (f14
));
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
);
153 __asm__
__volatile__ ("dtstdcq 5, %0, 1" : : "f" (f14
));
155 __asm__
__volatile__ ("dtstdcq 0, %0, 1" : : "f" (f14
));
159 __asm__
__volatile__ ("dtstdcq 5, %0, 2" : : "f" (f14
));
161 __asm__
__volatile__ ("dtstdcq 0, %0, 2" : : "f" (f14
));
165 __asm__
__volatile__ ("dtstdcq 5, %0, 4" : : "f" (f14
));
167 __asm__
__volatile__ ("dtstdcq 0, %0, 4" : : "f" (f14
));
171 __asm__
__volatile__ ("dtstdcq 5, %0, 8" : : "f" (f14
));
173 __asm__
__volatile__ ("dtstdcq 0, %0, 8" : : "f" (f14
));
177 __asm__
__volatile__ ("dtstdcq 5, %0, 16" : : "f" (f14
));
179 __asm__
__volatile__ ("dtstdcq 0, %0, 16" : : "f" (f14
));
183 __asm__
__volatile__ ("dtstdcq 5, %0, 32" : : "f" (f14
));
185 __asm__
__volatile__ ("dtstdcq 0, %0, 32" : : "f" (f14
));
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
);
208 __asm__
__volatile__ ("dtstdg 5, %0, 1" : : "f" (f14
));
210 __asm__
__volatile__ ("dtstdg 0, %0, 1" : : "f" (f14
));
214 __asm__
__volatile__ ("dtstdg 5, %0, 2" : : "f" (f14
));
216 __asm__
__volatile__ ("dtstdg 0, %0, 2" : : "f" (f14
));
220 __asm__
__volatile__ ("dtstdg 5, %0, 4" : : "f" (f14
));
222 __asm__
__volatile__ ("dtstdg 0, %0, 4" : : "f" (f14
));
226 __asm__
__volatile__ ("dtstdg 5, %0, 8" : : "f" (f14
));
228 __asm__
__volatile__ ("dtstdg 0, %0, 8" : : "f" (f14
));
232 __asm__
__volatile__ ("dtstdg 5, %0, 16" : : "f" (f14
));
234 __asm__
__volatile__ ("dtstdg 0, %0, 16" : : "f" (f14
));
238 __asm__
__volatile__ ("dtstdg 5, %0, 32" : : "f" (f14
));
240 __asm__
__volatile__ ("dtstdg 0, %0, 32" : : "f" (f14
));
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
);
257 __asm__
__volatile__ ("dtstdgq 5, %0, 1" : : "f" (f14
));
259 __asm__
__volatile__ ("dtstdgq 0, %0, 1" : : "f" (f14
));
263 __asm__
__volatile__ ("dtstdgq 5, %0, 2" : : "f" (f14
));
265 __asm__
__volatile__ ("dtstdgq 0, %0, 2" : : "f" (f14
));
269 __asm__
__volatile__ ("dtstdgq 5, %0, 4" : : "f" (f14
));
271 __asm__
__volatile__ ("dtstdgq 0, %0, 4" : : "f" (f14
));
275 __asm__
__volatile__ ("dtstdgq 5, %0, 8" : : "f" (f14
));
277 __asm__
__volatile__ ("dtstdgq 0, %0, 8" : : "f" (f14
));
281 __asm__
__volatile__ ("dtstdgq 5, %0, 16" : : "f" (f14
));
283 __asm__
__volatile__ ("dtstdgq 0, %0, 16" : : "f" (f14
));
287 __asm__
__volatile__ ("dtstdgq 5, %0, 32" : : "f" (f14
));
289 __asm__
__volatile__ ("dtstdgq 0, %0, 32" : : "f" (f14
));
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'.
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
);
311 __asm__
__volatile__ ("dtstex 4, %0, %1" : : "f" (f14
),"f" (f16
));
314 __asm__
__volatile__ ("dtstex 7, %0, %1" : : "f" (f14
),"f" (f16
));
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
);
331 __asm__
__volatile__ ("dtstexq 4, %0, %1" : : "f" (f14
),"f" (f16
));
334 __asm__
__volatile__ ("dtstexq 7, %0, %1" : : "f" (f14
),"f" (f16
));
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
;
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
373 0x2208000000000000ULL
, 0x0000000000000000ULL
,
374 0xa208000000000000ULL
, 0x0000000000000000ULL
, // negative
375 0xa248000000000000ULL
, 0x0000000000000000ULL
,
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
396 0x2238000000000000ULL
,
397 0xa238000000000000ULL
,
398 0x4248000000000000ULL
,
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
{
419 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests
420 static dfp_test_args_t dfp_2args_x1
[] = {
453 typedef struct dfp_test
455 test_funcp_t test_func
;
457 dfp_test_args_t
* targs
;
459 precision_type_t precision
;
463 typedef struct dfp_one_arg_test
465 test_funcp_t test_func
;
467 precision_type_t precision
;
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)
485 dfp_val_t test_val
, dummy
;
489 while ((func
= dfp_ClassAndGroupTest_tests
[k
].test_func
)) {
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;
497 if (test_def
.precision
== LONG_TEST
) {
498 test_val
.u64_val
= dfp64_vals
[i
];
500 test_val
.u128
.valu
= dfp128_vals
[i
* 2];
501 test_val
.u128
.vall
= dfp128_vals
[(i
* 2) + 1];
505 for (data_class_OR_group
= 0; data_class_OR_group
< 6; data_class_OR_group
++) {
506 unsigned int condreg
;
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
);
519 condreg
= ((flags
>> (4 * (7-BF
)))) & 0xf;
520 printf("%s (DC/DG=%d) %s", test_def
.name
, data_class_OR_group
,
522 if (test_def
.precision
== QUAD_TEST
) {
523 printf("%016llx %016llx", test_val
.u128
.valu
, test_val
.u128
.vall
);
525 printf("%016llx", test_val
.u64_val
);
529 printf(" => %x (BF=%d)\n", condreg
, BF
);
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
;
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
564 int i
, repeat
= 1, BF
= 4;
565 dfp_test_t test_def
= dfp_ExpTest_tests
[k
];
568 for (i
= 0; i
< test_def
.num_tests
; i
++) {
569 unsigned int condreg
;
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
];
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];
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
);
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
);
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
);
617 { &test_dfp_ExpTest_ops
,
618 "Test DFP exponent test instructions"},
619 { &test_dfp_ClassAndGroupTest_ops
,
620 "Test DFP class and group test instructions"},
629 test_driver_func_t func
;
632 while ((func
= all_tests
[i
].test_category
)) {
633 aTest
= all_tests
[i
];
634 printf( "%s\n", aTest
.name
);