You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
643 lines
21 KiB
643 lines
21 KiB
/* Copyright (C) 2012 IBM |
|
|
|
Author: Maynard Johnson <maynardj@us.ibm.com> |
|
|
|
This program is free software; you can redistribute it and/or |
|
modify it under the terms of the GNU General Public License as |
|
published by the Free Software Foundation; either version 2 of the |
|
License, or (at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, but |
|
WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program; if not, write to the Free Software |
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
|
02111-1307, USA. |
|
|
|
The GNU General Public License is contained in the file COPYING. |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <stdint.h> |
|
|
|
#if defined(HAS_DFP) |
|
|
|
typedef union stuff { |
|
_Decimal64 dec_val; |
|
_Decimal128 dec_val128; |
|
unsigned long long u64_val; |
|
struct { |
|
#if defined(VGP_ppc64le_linux) |
|
unsigned long long vall; |
|
unsigned long long valu; |
|
#else |
|
unsigned long long valu; |
|
unsigned long long vall; |
|
#endif |
|
} u128; |
|
} dfp_val_t; |
|
|
|
|
|
typedef unsigned char Bool; |
|
#define True 1 |
|
#define False 0 |
|
|
|
|
|
#define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7" |
|
|
|
#define SET_CR(_arg) \ |
|
__asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR ); |
|
|
|
#define SET_XER(_arg) \ |
|
__asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" ); |
|
|
|
#define GET_CR(_lval) \ |
|
__asm__ __volatile__ ("mfcr %0" : "=b"(_lval) ) |
|
|
|
#define GET_XER(_lval) \ |
|
__asm__ __volatile__ ("mfxer %0" : "=b"(_lval) ) |
|
|
|
#define GET_CR_XER(_lval_cr,_lval_xer) \ |
|
do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0) |
|
|
|
#define SET_CR_ZERO \ |
|
SET_CR(0) |
|
|
|
#define SET_XER_ZERO \ |
|
SET_XER(0) |
|
|
|
#define SET_CR_XER_ZERO \ |
|
do { SET_CR_ZERO; SET_XER_ZERO; } while (0) |
|
|
|
#define SET_FPSCR_ZERO \ |
|
do { double _d = 0.0; \ |
|
__asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \ |
|
} while (0) |
|
|
|
#define GET_FPSCR(_arg) \ |
|
__asm__ __volatile__ ("mffs %0" : "=f"(_arg) ) |
|
|
|
#define SET_FPSCR_DRN \ |
|
__asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) ) |
|
|
|
|
|
// The assembly-level instructions being tested |
|
|
|
/* In _test_dtstdc[q], DCM can be one of 6 possible data classes, numbered 0-5. |
|
* In reality, DCM is a 6-bit mask field. We just test the individual values |
|
* and assume that masking multiple values would work OK. |
|
* BF is the condition register bit field which can range from 0-7. But for |
|
* testing purposes, we only use BF values of '0' and '5'. |
|
*/ |
|
static void _test_dtstdc(int BF, int DCM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused))) |
|
{ |
|
_Decimal64 f14 = val1->dec_val; |
|
if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) { |
|
fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM); |
|
return; |
|
} |
|
switch (DCM) { |
|
case 0: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdc 5, %0, 1" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdc 0, %0, 1" : : "f" (f14)); |
|
break; |
|
case 1: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdc 5, %0, 2" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdc 0, %0, 2" : : "f" (f14)); |
|
break; |
|
case 2: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdc 5, %0, 4" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdc 0, %0, 4" : : "f" (f14)); |
|
break; |
|
case 3: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdc 5, %0, 8" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdc 0, %0, 8" : : "f" (f14)); |
|
break; |
|
case 4: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdc 5, %0, 16" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdc 0, %0, 16" : : "f" (f14)); |
|
break; |
|
case 5: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdc 5, %0, 32" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdc 0, %0, 32" : : "f" (f14)); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static void _test_dtstdcq(int BF, int DCM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused))) |
|
{ |
|
_Decimal128 f14 = val1->dec_val128; |
|
if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) { |
|
fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM); |
|
return; |
|
} |
|
switch (DCM) { |
|
case 0: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdcq 5, %0, 1" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdcq 0, %0, 1" : : "f" (f14)); |
|
break; |
|
case 1: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdcq 5, %0, 2" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdcq 0, %0, 2" : : "f" (f14)); |
|
break; |
|
case 2: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdcq 5, %0, 4" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdcq 0, %0, 4" : : "f" (f14)); |
|
break; |
|
case 3: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdcq 5, %0, 8" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdcq 0, %0, 8" : : "f" (f14)); |
|
break; |
|
case 4: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdcq 5, %0, 16" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdcq 0, %0, 16" : : "f" (f14)); |
|
break; |
|
case 5: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdcq 5, %0, 32" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdcq 0, %0, 32" : : "f" (f14)); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
/* In _test_dtstdg[q], DGM can be one of 6 possible data groups, numbered 0-5. |
|
* In reality, DGM is a 6-bit mask field. We just test the individual values |
|
* and assume that masking multiple values would work OK. |
|
* BF is the condition register bit field which can range from 0-7. But for |
|
* testing purposes, we only use BF values of '0' and '5'. |
|
*/ |
|
static void _test_dtstdg(int BF, int DGM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused))) |
|
{ |
|
_Decimal64 f14 = val1->dec_val; |
|
if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) { |
|
fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM); |
|
return; |
|
} |
|
switch (DGM) { |
|
case 0: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdg 5, %0, 1" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdg 0, %0, 1" : : "f" (f14)); |
|
break; |
|
case 1: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdg 5, %0, 2" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdg 0, %0, 2" : : "f" (f14)); |
|
break; |
|
case 2: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdg 5, %0, 4" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdg 0, %0, 4" : : "f" (f14)); |
|
break; |
|
case 3: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdg 5, %0, 8" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdg 0, %0, 8" : : "f" (f14)); |
|
break; |
|
case 4: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdg 5, %0, 16" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdg 0, %0, 16" : : "f" (f14)); |
|
break; |
|
case 5: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdg 5, %0, 32" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdg 0, %0, 32" : : "f" (f14)); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static void _test_dtstdgq(int BF, int DGM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused))) |
|
{ |
|
_Decimal128 f14 = val1->dec_val128; |
|
if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) { |
|
fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM); |
|
return; |
|
} |
|
switch (DGM) { |
|
case 0: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdgq 5, %0, 1" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdgq 0, %0, 1" : : "f" (f14)); |
|
break; |
|
case 1: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdgq 5, %0, 2" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdgq 0, %0, 2" : : "f" (f14)); |
|
break; |
|
case 2: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdgq 5, %0, 4" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdgq 0, %0, 4" : : "f" (f14)); |
|
break; |
|
case 3: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdgq 5, %0, 8" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdgq 0, %0, 8" : : "f" (f14)); |
|
break; |
|
case 4: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdgq 5, %0, 16" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdgq 0, %0, 16" : : "f" (f14)); |
|
break; |
|
case 5: |
|
if (BF) |
|
__asm__ __volatile__ ("dtstdgq 5, %0, 32" : : "f" (f14)); |
|
else |
|
__asm__ __volatile__ ("dtstdgq 0, %0, 32" : : "f" (f14)); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
/* In _test_dtstex[q], BF is the condition register bit field indicating the |
|
* CR field in which the result of the test should be placed. BF can range |
|
* from 0-7, but for testing purposes, we only use BF values of '4' and '7'. |
|
*/ |
|
static void |
|
_test_dtstex(int BF, int x __attribute__((unused)), dfp_val_t *val1, dfp_val_t *val2) |
|
{ |
|
_Decimal64 f14 = val1->dec_val; |
|
_Decimal64 f16 = val2->dec_val; |
|
if (!(BF == 4 || BF == 7)) { |
|
fprintf(stderr, "Invalid input to asm test: a=%d\n", BF); |
|
return; |
|
} |
|
switch (BF) { |
|
case 4: |
|
__asm__ __volatile__ ("dtstex 4, %0, %1" : : "f" (f14),"f" (f16)); |
|
break; |
|
case 7: |
|
__asm__ __volatile__ ("dtstex 7, %0, %1" : : "f" (f14),"f" (f16)); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
static void _test_dtstexq(int BF, int x __attribute__((unused)), dfp_val_t *val1, dfp_val_t *val2) |
|
{ |
|
_Decimal128 f14 = val1->dec_val128; |
|
_Decimal128 f16 = val2->dec_val128; |
|
if (!(BF == 4 || BF == 7)) { |
|
fprintf(stderr, "Invalid input to asm test: a=%d\n", BF); |
|
return; |
|
} |
|
switch (BF) { |
|
case 4: |
|
__asm__ __volatile__ ("dtstexq 4, %0, %1" : : "f" (f14),"f" (f16)); |
|
break; |
|
case 7: |
|
__asm__ __volatile__ ("dtstexq 7, %0, %1" : : "f" (f14),"f" (f16)); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
|
|
|
|
typedef void (*test_funcp_t)(int a, int b, dfp_val_t *val1, dfp_val_t *val2); |
|
typedef void (*test_driver_func_t)(void); |
|
typedef struct test_table |
|
{ |
|
test_driver_func_t test_category; |
|
char * name; |
|
} test_table_t; |
|
|
|
/* |
|
* 345.0DD (0x2207c00000000000 0xe50) |
|
* 1.2300e+5DD (0x2207c00000000000 0x14c000) |
|
* -16.0DD (0xa207c00000000000 0xe0) |
|
* 0.00189DD (0x2206c00000000000 0xcf) |
|
* -4.1235DD (0xa205c00000000000 0x10a395bcf) |
|
* 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4) |
|
* 0DD (0x2208000000000000 0x0) |
|
* 0DD (0x2208000000000000 0x0) |
|
* infDD (0x7800000000000000 0x0) |
|
* nanDD (0x7c00000000000000 0x0 |
|
*/ |
|
static unsigned long long dfp128_vals[] = { |
|
// Some finite numbers |
|
0x2207c00000000000ULL, 0x0000000000000e50ULL, |
|
0x2207c00000000000ULL, 0x000000000014c000ULL, |
|
0xa207c00000000000ULL, 0x00000000000000e0ULL, |
|
0x2206c00000000000ULL, 0x00000000000000cfULL, |
|
0xa205c00000000000ULL, 0x000000010a395bcfULL, |
|
0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number |
|
0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number |
|
// flavors of zero |
|
0x2208000000000000ULL, 0x0000000000000000ULL, |
|
0xa208000000000000ULL, 0x0000000000000000ULL, // negative |
|
0xa248000000000000ULL, 0x0000000000000000ULL, |
|
// flavors of NAN |
|
0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet |
|
0xfc00000000000000ULL, 0xc00100035b007700ULL, |
|
0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling |
|
// flavors of Infinity |
|
0x7800000000000000ULL, 0x0000000000000000ULL, |
|
0xf800000000000000ULL, 0x0000000000000000ULL, // negative |
|
0xf900000000000000ULL, 0x0000000000000000ULL |
|
}; |
|
|
|
static unsigned long long dfp64_vals[] = { |
|
// various finite numbers |
|
0x2234000000000e50ULL, |
|
0x223400000014c000ULL, |
|
0xa2340000000000e0ULL,// negative |
|
0x22240000000000cfULL, |
|
0xa21400010a395bcfULL,// negative |
|
0x6e4d3f1f534acdd4ULL,// huge number |
|
0x000400000089b000ULL,// very small number |
|
// flavors of zero |
|
0x2238000000000000ULL, |
|
0xa238000000000000ULL, |
|
0x4248000000000000ULL, |
|
// flavors of NAN |
|
0x7e34000000000111ULL, |
|
0xfe000000d0e0a0d0ULL,//signaling |
|
0xfc00000000000000ULL,//quiet |
|
// flavors of Infinity |
|
0x7800000000000000ULL, |
|
0xf800000000000000ULL,//negative |
|
0x7a34000000000000ULL, |
|
}; |
|
|
|
// Both Long and Quad arrays of DFP values should have the same length, so it |
|
// doesn't matter which array I use for calculating the following #define. |
|
#define NUM_DFP_VALS (sizeof(dfp64_vals)/8) |
|
|
|
typedef struct dfp_test_args { |
|
int fra_idx; |
|
int frb_idx; |
|
} dfp_test_args_t; |
|
|
|
|
|
// Index pairs from dfp64_vals array to be used with dfp_two_arg_tests |
|
static dfp_test_args_t dfp_2args_x1[] = { |
|
{0, 1}, |
|
{2, 1}, |
|
{4, 3}, |
|
{6, 0}, |
|
{2, 4}, |
|
{5, 1}, |
|
{5, 2}, |
|
{7, 1}, |
|
{7, 2}, |
|
{8, 0}, |
|
{8, 1}, |
|
{8, 2}, |
|
{7, 8}, |
|
{12, 14}, |
|
{12, 1}, |
|
{12, 13}, |
|
{12, 12}, |
|
{12, 11}, |
|
{11, 14}, |
|
{11, 0}, |
|
{11, 13}, |
|
{11, 11}, |
|
{14, 14}, |
|
{14, 3}, |
|
{14, 15}, |
|
}; |
|
|
|
typedef enum { |
|
LONG_TEST, |
|
QUAD_TEST |
|
} precision_type_t; |
|
|
|
typedef struct dfp_test |
|
{ |
|
test_funcp_t test_func; |
|
const char * name; |
|
dfp_test_args_t * targs; |
|
int num_tests; |
|
precision_type_t precision; |
|
const char * op; |
|
} dfp_test_t; |
|
|
|
typedef struct dfp_one_arg_test |
|
{ |
|
test_funcp_t test_func; |
|
const char * name; |
|
precision_type_t precision; |
|
const char * op; |
|
} dfp_one_arg_test_t; |
|
|
|
|
|
|
|
static dfp_one_arg_test_t |
|
dfp_ClassAndGroupTest_tests[] = { |
|
{ &_test_dtstdc, "dtstdc", LONG_TEST, "[tCls]"}, |
|
{ &_test_dtstdcq, "dtstdcq", QUAD_TEST, "[tCls]"}, |
|
{ &_test_dtstdg, "dtstdg", LONG_TEST, "[tGrp]"}, |
|
{ &_test_dtstdgq, "dtstdgq", QUAD_TEST, "[tGrp]"}, |
|
{ NULL, NULL, 0, NULL} |
|
}; |
|
|
|
static void test_dfp_ClassAndGroupTest_ops(void) |
|
{ |
|
test_funcp_t func; |
|
dfp_val_t test_val, dummy; |
|
|
|
int k = 0; |
|
|
|
while ((func = dfp_ClassAndGroupTest_tests[k].test_func)) { |
|
int i; |
|
dfp_one_arg_test_t test_def = dfp_ClassAndGroupTest_tests[k]; |
|
|
|
for (i = 0; i < NUM_DFP_VALS; i++) { |
|
int data_class_OR_group, BF = 0; |
|
Bool repeat = True; |
|
|
|
if (test_def.precision == LONG_TEST) { |
|
test_val.u64_val = dfp64_vals[i]; |
|
} else { |
|
test_val.u128.valu = dfp128_vals[i * 2]; |
|
test_val.u128.vall = dfp128_vals[(i * 2) + 1]; |
|
} |
|
|
|
again: |
|
for (data_class_OR_group = 0; data_class_OR_group < 6; data_class_OR_group++) { |
|
unsigned int condreg; |
|
unsigned int flags; |
|
SET_FPSCR_ZERO; |
|
SET_CR_XER_ZERO; |
|
|
|
/* There is an ABI change in how 128 bit arguments are aligned |
|
* with GCC 5.0. The compiler generates a "note" about this |
|
* starting with GCC 4.8. To avoid generating the "note", pass |
|
* the address of the 128-bit arguments rather then the value. |
|
*/ |
|
(*func)(BF, data_class_OR_group, &test_val, &dummy); |
|
GET_CR(flags); |
|
|
|
condreg = ((flags >> (4 * (7-BF)))) & 0xf; |
|
printf("%s (DC/DG=%d) %s", test_def.name, data_class_OR_group, |
|
test_def.op); |
|
if (test_def.precision == QUAD_TEST) { |
|
printf("%016llx %016llx", test_val.u128.valu, test_val.u128.vall); |
|
} else { |
|
printf("%016llx", test_val.u64_val); |
|
} |
|
|
|
//%016llx |
|
printf(" => %x (BF=%d)\n", condreg, BF); |
|
} |
|
if (repeat) { |
|
repeat = False; |
|
BF = 5; |
|
goto again; |
|
} |
|
} |
|
k++; |
|
printf( "\n" ); |
|
} |
|
} |
|
|
|
|
|
static dfp_test_t |
|
dfp_ExpTest_tests[] = { |
|
{ &_test_dtstex, "dtstex", dfp_2args_x1, 25, LONG_TEST, "[tExp]"}, |
|
{ &_test_dtstexq, "dtstexq", dfp_2args_x1, 25, QUAD_TEST, "[tExp]"}, |
|
{ NULL, NULL, NULL, 0, 0, NULL} |
|
}; |
|
|
|
|
|
static void test_dfp_ExpTest_ops(void) |
|
{ |
|
dfp_val_t test_val1, test_val2; |
|
test_funcp_t func; |
|
int k = 0; |
|
|
|
while ((func = dfp_ExpTest_tests[k].test_func)) { |
|
/* BF is a 3-bit instruction field that indicates the CR field in which the |
|
* result of the test should be placed. We won't iterate through all |
|
* 8 possible BF values since storing compare results to a given field is |
|
* a well-tested mechanism in VEX. But we will test two BF values, just as |
|
* a sniff-test. |
|
*/ |
|
int i, repeat = 1, BF = 4; |
|
dfp_test_t test_def = dfp_ExpTest_tests[k]; |
|
|
|
again: |
|
for (i = 0; i < test_def.num_tests; i++) { |
|
unsigned int condreg; |
|
unsigned int flags; |
|
|
|
if (test_def.precision == LONG_TEST) { |
|
test_val1.u64_val = dfp64_vals[test_def.targs[i].fra_idx]; |
|
test_val2.u64_val = dfp64_vals[test_def.targs[i].frb_idx]; |
|
} else { |
|
test_val1.u128.valu = dfp128_vals[test_def.targs[i].fra_idx * 2]; |
|
test_val1.u128.vall = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1]; |
|
test_val2.u128.valu = dfp128_vals[test_def.targs[i].frb_idx * 2]; |
|
test_val2.u128.vall = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1]; |
|
} |
|
|
|
SET_FPSCR_ZERO; |
|
SET_CR_XER_ZERO; |
|
/* There is an ABI change in how 128 bit arguments are aligned |
|
* with GCC 5.0. The compiler generates a "note" about this |
|
* starting with GCC 4.8. To avoid generating the "note", pass |
|
* the address of the 128-bit arguments rather then the value. |
|
*/ |
|
(*func)(BF, 0, &test_val1, &test_val2); |
|
GET_CR(flags); |
|
|
|
condreg = ((flags >> (4 * (7-BF)))) & 0xf; |
|
printf("%s ", test_def.name); |
|
if (test_def.precision == LONG_TEST) { |
|
printf("%016llx %s %016llx ", |
|
test_val1.u64_val, test_def.op, test_val2.u64_val); |
|
} else { |
|
printf("%016llx %016llx %s %016llx %016llx ", |
|
test_val1.u128.valu, test_val1.u128.vall, test_def.op, test_val2.u128.valu, test_val2.u128.vall); |
|
} |
|
printf(" => %x (BF=%d)\n", condreg, BF); |
|
} |
|
if (repeat) { |
|
repeat = 0; |
|
BF = 7; |
|
goto again; |
|
} |
|
k++; |
|
printf( "\n" ); |
|
} |
|
} |
|
|
|
|
|
static test_table_t |
|
all_tests[] = |
|
{ |
|
{ &test_dfp_ExpTest_ops, |
|
"Test DFP exponent test instructions"}, |
|
{ &test_dfp_ClassAndGroupTest_ops, |
|
"Test DFP class and group test instructions"}, |
|
{ NULL, NULL } |
|
}; |
|
#endif // HAS_DFP |
|
|
|
int main() { |
|
#if defined(HAS_DFP) |
|
|
|
test_table_t aTest; |
|
test_driver_func_t func; |
|
int i = 0; |
|
|
|
while ((func = all_tests[i].test_category)) { |
|
aTest = all_tests[i]; |
|
printf( "%s\n", aTest.name ); |
|
(*func)(); |
|
i++; |
|
} |
|
|
|
#endif // HAS_DFP |
|
return 0; |
|
}
|
|
|