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 floating-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 } 91