| 1 |
root |
1.1 |
/* Beginning of modification history */ |
| 2 |
|
|
/* Written 02-04-10 by Paul Green (Paul.Green@stratus.com) */ |
| 3 |
|
|
/* End of modification history */ |
| 4 |
|
|
|
| 5 |
|
|
/* This test case is extracted from Perl version 5.7.3. It is |
| 6 |
|
|
in the Perl_unpack_str function of the pp_pack.c source file. |
| 7 |
|
|
|
| 8 |
|
|
GCC 2.95.2 improperly assumes that it can compensate for an |
| 9 |
|
|
extra fsub by performing a fadd. This would work in |
| 10 |
|
|
fixed-point arithmetic, but does not work in floating-point |
| 11 |
|
|
arithmetic. |
| 12 |
|
|
|
| 13 |
|
|
This problem has been seen on HP-UX and on Stratus VOS, both |
| 14 |
|
|
of which have an HP PA-RISC target (hppa1.1). The Stratus |
| 15 |
|
|
bug number is gnu_g++-220. */ |
| 16 |
|
|
|
| 17 |
|
|
/* #define _POSIX_C_SOURCE 199506L -- added by Configure */ |
| 18 |
|
|
#include <stdio.h> |
| 19 |
|
|
#include <string.h> |
| 20 |
|
|
#include <math.h> |
| 21 |
|
|
|
| 22 |
|
|
void test(double *result) |
| 23 |
|
|
{ |
| 24 |
|
|
float afloat; |
| 25 |
|
|
double adouble; |
| 26 |
|
|
int checksum = 0; |
| 27 |
|
|
unsigned cuv = 0; |
| 28 |
|
|
double cdouble = 0.0; |
| 29 |
|
|
const int bits_in_uv = 8 * sizeof(cuv); |
| 30 |
|
|
|
| 31 |
|
|
checksum = 53; |
| 32 |
|
|
cdouble = -1.0; |
| 33 |
|
|
|
| 34 |
|
|
if (checksum) { |
| 35 |
|
|
if (checksum > bits_in_uv) { |
| 36 |
|
|
double trouble; |
| 37 |
|
|
|
| 38 |
|
|
adouble = (double) (1 << (checksum & 15)); |
| 39 |
|
|
|
| 40 |
|
|
while (checksum >= 16) { |
| 41 |
|
|
checksum -= 16; |
| 42 |
|
|
adouble *= 65536.0; |
| 43 |
|
|
} |
| 44 |
|
|
|
| 45 |
|
|
/* At -O1, GCC 2.95.2 compiles the following loop |
| 46 |
|
|
into: |
| 47 |
|
|
|
| 48 |
|
|
L$0014 |
| 49 |
|
|
fcmp,dbl,>= %fr4,%fr0 |
| 50 |
|
|
ftest |
| 51 |
|
|
b L$0014 |
| 52 |
|
|
fadd,dbl %fr4,%fr12,%fr4 |
| 53 |
|
|
fsub,dbl %fr4,%fr12,%fr4 |
| 54 |
|
|
|
| 55 |
|
|
This code depends on the floading-add and |
| 56 |
|
|
floating-subtract retaining all of the |
| 57 |
|
|
precision present in the operands. There is |
| 58 |
|
|
no such guarantee when using floating-point, |
| 59 |
|
|
as this test case demonstrates. |
| 60 |
|
|
|
| 61 |
|
|
The code is okay at -O0. */ |
| 62 |
|
|
|
| 63 |
|
|
while (cdouble < 0.0) |
| 64 |
|
|
cdouble += adouble; |
| 65 |
|
|
|
| 66 |
|
|
cdouble = modf (cdouble / adouble, &trouble) * adouble; |
| 67 |
|
|
} |
| 68 |
|
|
} |
| 69 |
|
|
|
| 70 |
|
|
*result = cdouble; |
| 71 |
|
|
} |
| 72 |
|
|
|
| 73 |
|
|
int main (int argc, char ** argv) |
| 74 |
|
|
{ |
| 75 |
|
|
double value; |
| 76 |
|
|
|
| 77 |
|
|
test (&value); |
| 78 |
|
|
|
| 79 |
|
|
if (argc == 2 && !strcmp(argv[1],"-v")) |
| 80 |
|
|
printf ("value = %.18e\n", value); |
| 81 |
|
|
|
| 82 |
|
|
if (value != 9.007199254740991e+15) { |
| 83 |
|
|
printf ("t001 fails!\n"); |
| 84 |
|
|
return -1; |
| 85 |
|
|
} |
| 86 |
|
|
else { |
| 87 |
|
|
printf ("t001 works.\n"); |
| 88 |
|
|
return 0; |
| 89 |
|
|
} |
| 90 |
|
|
} |