diff options
author | Raymond Lu <songyulu@hdfgroup.org> | 2010-10-28 19:08:31 (GMT) |
---|---|---|
committer | Raymond Lu <songyulu@hdfgroup.org> | 2010-10-28 19:08:31 (GMT) |
commit | 1e55692d9a41b05f8a8c14c4745cef71c9b4851e (patch) | |
tree | b9acde7122343e37cce7009fb8946e5ebb04d91c | |
parent | 751b307df9208102042e205c360ef184c76f10fc (diff) | |
download | hdf5-1e55692d9a41b05f8a8c14c4745cef71c9b4851e.zip hdf5-1e55692d9a41b05f8a8c14c4745cef71c9b4851e.tar.gz hdf5-1e55692d9a41b05f8a8c14c4745cef71c9b4851e.tar.bz2 |
[svn-r19696] Bug 2008 - IBM Power6 Linux uses special conversion algorithms to convert some values from long
double to (unsigned) long and from (unsigned) long to long double. I added tests in configure.in
to detect these algorithms. Before I can figure out them, I disable the tests in dt_arith.c.
There are property changes to tools/misc, config, and Makefile.am when I brought the fix from 1.8.
Tested on jam, heiwa, amani, IBM Power6 Linux machine in Holland (huygens.sara.nl).
-rwxr-xr-x | configure | 197 | ||||
-rw-r--r-- | configure.in | 162 | ||||
-rw-r--r-- | src/H5config.h.in | 8 | ||||
-rw-r--r-- | test/dt_arith.c | 32 |
4 files changed, 399 insertions, 0 deletions
@@ -27588,6 +27588,202 @@ else $as_echo "no" >&6; } fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if using special algorithm to convert long double to (unsigned) long values" >&5 +$as_echo_n "checking if using special algorithm to convert long double to (unsigned) long values... " >&6; } + +if test ${ac_cv_sizeof_long_double} = 0; then + hdf5_cv_ldouble_to_long_special=${hdf5_cv_ldouble_to_long_special=no} +else + if test "${hdf5_cv_ldouble_to_long_special+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + int main(void) + { + long double ld = 20041683600089727.779961L; + long ll; + unsigned long ull; + unsigned char s[16]; + unsigned char s2[8]; + int ret = 1; + + if(sizeof(long double) == 16 && sizeof(long) == 8) { + /*make sure the long double type has 16 bytes in size and + * 11 bits of exponent. If it is, + *the bit sequence should be like below. It's not + *a decent way to check but this info isn't available. */ + memcpy(s, &ld, 16); + if(s[0]==0x43 && s[1]==0x51 && s[2]==0xcc && s[3]==0xf3 && + s[4]==0x85 && s[5]==0xeb && s[6]==0xc8 && s[7]==0xa0 && + s[8]==0xbf && s[9]==0xcc && s[10]==0x2a && s[11]==0x3c) { + + /* Assign the hexadecimal value of long double type. */ + s[0]=0x43; s[1]=0x51; s[2]=0xcc; s[3]=0xf3; + s[4]=0x85; s[5]=0xeb; s[6]=0xc8; s[7]=0xa0; + s[8]=0xbf; s[9]=0xcc; s[10]=0x2a; s[11]=0x3c; + s[12]=0x3d; s[13]=0x85; s[14]=0x56; s[15]=0x20; + + memcpy(&ld, s, 16); + + ll = (long)ld; + memcpy(s2, &ll, 8); + + /* The library's algorithm converts it to 0x 00 47 33 ce 17 af 22 82 + * and gets wrong value 20041683600089730 on the IBM Power6 Linux. + * But the IBM Power6 Linux converts it to 0x00 47 33 ce 17 af 22 7f + * and gets the correct value 20041683600089727. It uses some special + * algorithm. We're going to define the macro and skip the test until + * we can figure out how they do it. */ + if(s2[0]==0x00 && s2[1]==0x47 && s2[2]==0x33 && s2[3]==0xce && + s2[4]==0x17 && s2[5]==0xaf && s2[6]==0x22 && s2[7]==0x7f) + ret = 0; + + ull = (unsigned long)ld; + memcpy(s2, &ull, 8); + + /* The unsigned long is the same as signed long. */ + if(s2[0]==0x00 && s2[1]==0x47 && s2[2]==0x33 && s2[3]==0xce && + s2[4]==0x17 && s2[5]==0xaf && s2[6]==0x22 && s2[7]==0x7f) + ret = 0; + } + } + + done: + exit(ret); + } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + hdf5_cv_ldouble_to_long_special=yes +else + hdf5_cv_ldouble_to_long_special=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + +fi + +if test ${hdf5_cv_ldouble_to_long_special} = "yes"; then + +$as_echo "#define LDOUBLE_TO_LONG_SPECIAL 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if using special algorithm to convert (unsigned) long to long double values" >&5 +$as_echo_n "checking if using special algorithm to convert (unsigned) long to long double values... " >&6; } + +if test ${ac_cv_sizeof_long_double} = 0; then + hdf5_cv_long_to_ldouble_special=${hdf5_cv_long_to_ldouble_special=no} +else + if test "${hdf5_cv_long_to_ldouble_special+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + int main(void) + { + long double ld; + long ll; + unsigned long ull; + unsigned char s[16]; + int flag=0, ret=1; + + /*Determine if long double has 16 byte in size, 11 bit exponent, and + *the bias is 0x3ff */ + if(sizeof(long double) == 16) { + ld = 1.0L; + memcpy(s, &ld, 16); + if(s[0]==0x3f && s[1]==0xf0 && s[2]==0x00 && s[3]==0x00 && + s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00) + flag = 1; + } + + if(flag==1 && sizeof(long)==8) { + ll = 0x003fffffffffffffL; + ld = (long double)ll; + memcpy(s, &ld, 16); + /* The library converts the value to 0x434fffffffffffff8000000000000000. + * In decimal it is 18014398509481982.000000, one value short of the original. + * The IBM Power6 Linux converts it to 0x4350000000000000bff0000000000000. + * The value is correct in decimal. It uses some special + * algorithm. We're going to define the macro and skip the test until + * we can figure out how they do it. */ + if(s[0]==0x43 && s[1]==0x50 && s[2]==0x00 && s[3]==0x00 && + s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00 && + s[8]==0xbf && s[9]==0xf0 && s[10]==0x00 && s[11]==0x00 && + s[12]==0x00 && s[13]==0x00 && s[14]==0x00 && s[15]==0x00) + ret = 0; + } + if(flag==1 && sizeof(unsigned long)==8) { + ull = 0xffffffffffffffffUL; + ld = (long double)ull; + memcpy(s, &ld, 16); + /* Use a different value from signed long to test. The problem is the same + * for both long and unsigned long. The value is 18446744073709551615. + * The library converts the value to 0x43effffffffffffffe000000000000000. + * In decimal it's 18446744073709548544.000000, very different from the original. + * The IBM Power6 Linux converts it to 0x43f0000000000000bff0000000000000. + * The value is correct in decimal. It uses some special + * algorithm. We're going to define the macro and skip the test until + * we can figure out how they do it. */ + if(s[0]==0x43 && s[1]==0xf0 && s[2]==0x00 && s[3]==0x00 && + s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00 && + s[8]==0xbf && s[9]==0xf0 && s[10]==0x00 && s[11]==0x00 && + s[12]==0x00 && s[13]==0x00 && s[14]==0x00 && s[15]==0x00) + ret = 0; + } + done: + exit(ret); + } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + hdf5_cv_long_to_ldouble_special=yes +else + hdf5_cv_long_to_ldouble_special=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + +fi + +if test ${hdf5_cv_long_to_ldouble_special} = "yes"; then + +$as_echo "#define LONG_TO_LDOUBLE_SPECIAL 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if correctly converting long double to (unsigned) long long values" >&5 $as_echo_n "checking if correctly converting long double to (unsigned) long long values... " >&6; } @@ -27668,6 +27864,7 @@ else $as_echo "no" >&6; } fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if correctly converting (unsigned) long long to long double values" >&5 $as_echo_n "checking if correctly converting (unsigned) long long to long double values... " >&6; } diff --git a/configure.in b/configure.in index c75c4a7..107ebe7 100644 --- a/configure.in +++ b/configure.in @@ -3548,6 +3548,167 @@ else fi dnl ---------------------------------------------------------------------- +dnl Set the flag to indicate that the machine is using a special algorithm to convert +dnl 'long double' to '(unsigned) long' values. (This flag should only be set for +dnl the IBM Power6 Linux. When the bit sequence of long double is +dnl 0x4351ccf385ebc8a0bfcc2a3c3d855620, the converted value of (unsigned)long +dnl is 0x004733ce17af227f, not the same as the library's conversion to 0x004733ce17af2282. +dnl The machine's conversion gets the correct value. We define the macro and disable +dnl this kind of test until we figure out what algorithm they use. +dnl +AC_MSG_CHECKING([if using special algorithm to convert long double to (unsigned) long values]) + +if test ${ac_cv_sizeof_long_double} = 0; then + hdf5_cv_ldouble_to_long_special=${hdf5_cv_ldouble_to_long_special=no} +else + AC_CACHE_VAL([hdf5_cv_ldouble_to_long_special], + [AC_TRY_RUN([ + int main(void) + { + long double ld = 20041683600089727.779961L; + long ll; + unsigned long ull; + unsigned char s[16]; + unsigned char s2[8]; + int ret = 1; + + if(sizeof(long double) == 16 && sizeof(long) == 8) { + /*make sure the long double type has 16 bytes in size and + * 11 bits of exponent. If it is, + *the bit sequence should be like below. It's not + *a decent way to check but this info isn't available. */ + memcpy(s, &ld, 16); + if(s[0]==0x43 && s[1]==0x51 && s[2]==0xcc && s[3]==0xf3 && + s[4]==0x85 && s[5]==0xeb && s[6]==0xc8 && s[7]==0xa0 && + s[8]==0xbf && s[9]==0xcc && s[10]==0x2a && s[11]==0x3c) { + + /* Assign the hexadecimal value of long double type. */ + s[0]=0x43; s[1]=0x51; s[2]=0xcc; s[3]=0xf3; + s[4]=0x85; s[5]=0xeb; s[6]=0xc8; s[7]=0xa0; + s[8]=0xbf; s[9]=0xcc; s[10]=0x2a; s[11]=0x3c; + s[12]=0x3d; s[13]=0x85; s[14]=0x56; s[15]=0x20; + + memcpy(&ld, s, 16); + + ll = (long)ld; + memcpy(s2, &ll, 8); + + /* The library's algorithm converts it to 0x 00 47 33 ce 17 af 22 82 + * and gets wrong value 20041683600089730 on the IBM Power6 Linux. + * But the IBM Power6 Linux converts it to 0x00 47 33 ce 17 af 22 7f + * and gets the correct value 20041683600089727. It uses some special + * algorithm. We're going to define the macro and skip the test until + * we can figure out how they do it. */ + if(s2[0]==0x00 && s2[1]==0x47 && s2[2]==0x33 && s2[3]==0xce && + s2[4]==0x17 && s2[5]==0xaf && s2[6]==0x22 && s2[7]==0x7f) + ret = 0; + + ull = (unsigned long)ld; + memcpy(s2, &ull, 8); + + /* The unsigned long is the same as signed long. */ + if(s2[0]==0x00 && s2[1]==0x47 && s2[2]==0x33 && s2[3]==0xce && + s2[4]==0x17 && s2[5]==0xaf && s2[6]==0x22 && s2[7]==0x7f) + ret = 0; + } + } + + done: + exit(ret); + } + ], [hdf5_cv_ldouble_to_long_special=yes], [hdf5_cv_ldouble_to_long_special=no],)]) +fi + +if test ${hdf5_cv_ldouble_to_long_special} = "yes"; then + AC_DEFINE([LDOUBLE_TO_LONG_SPECIAL], [1], + [Define if your system converts long double to (unsigned) long values with special algorithm.]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +dnl ---------------------------------------------------------------------- +dnl Set the flag to indicate that the machine is using a special algorithm +dnl to convert some values of '(unsigned) long' to 'long double' values. +dnl (This flag should be off for all machines, except for IBM Power6 Linux, +dnl when the bit sequences are 003fff..., 007fff..., 00ffff..., 01ffff..., +dnl ..., 7fffff..., the compiler uses a unknown algorithm. We define a +dnl macro and skip the test for now until we know about the algorithm. +dnl +AC_MSG_CHECKING([if using special algorithm to convert (unsigned) long to long double values]) + +if test ${ac_cv_sizeof_long_double} = 0; then + hdf5_cv_long_to_ldouble_special=${hdf5_cv_long_to_ldouble_special=no} +else + AC_CACHE_VAL([hdf5_cv_long_to_ldouble_special], + [AC_TRY_RUN([ + int main(void) + { + long double ld; + long ll; + unsigned long ull; + unsigned char s[16]; + int flag=0, ret=1; + + /*Determine if long double has 16 byte in size, 11 bit exponent, and + *the bias is 0x3ff */ + if(sizeof(long double) == 16) { + ld = 1.0L; + memcpy(s, &ld, 16); + if(s[0]==0x3f && s[1]==0xf0 && s[2]==0x00 && s[3]==0x00 && + s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00) + flag = 1; + } + + if(flag==1 && sizeof(long)==8) { + ll = 0x003fffffffffffffL; + ld = (long double)ll; + memcpy(s, &ld, 16); + /* The library converts the value to 0x434fffffffffffff8000000000000000. + * In decimal it is 18014398509481982.000000, one value short of the original. + * The IBM Power6 Linux converts it to 0x4350000000000000bff0000000000000. + * The value is correct in decimal. It uses some special + * algorithm. We're going to define the macro and skip the test until + * we can figure out how they do it. */ + if(s[0]==0x43 && s[1]==0x50 && s[2]==0x00 && s[3]==0x00 && + s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00 && + s[8]==0xbf && s[9]==0xf0 && s[10]==0x00 && s[11]==0x00 && + s[12]==0x00 && s[13]==0x00 && s[14]==0x00 && s[15]==0x00) + ret = 0; + } + if(flag==1 && sizeof(unsigned long)==8) { + ull = 0xffffffffffffffffUL; + ld = (long double)ull; + memcpy(s, &ld, 16); + /* Use a different value from signed long to test. The problem is the same + * for both long and unsigned long. The value is 18446744073709551615. + * The library converts the value to 0x43effffffffffffffe000000000000000. + * In decimal it's 18446744073709548544.000000, very different from the original. + * The IBM Power6 Linux converts it to 0x43f0000000000000bff0000000000000. + * The value is correct in decimal. It uses some special + * algorithm. We're going to define the macro and skip the test until + * we can figure out how they do it. */ + if(s[0]==0x43 && s[1]==0xf0 && s[2]==0x00 && s[3]==0x00 && + s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00 && + s[8]==0xbf && s[9]==0xf0 && s[10]==0x00 && s[11]==0x00 && + s[12]==0x00 && s[13]==0x00 && s[14]==0x00 && s[15]==0x00) + ret = 0; + } + done: + exit(ret); + } + ], [hdf5_cv_long_to_ldouble_special=yes], [hdf5_cv_long_to_ldouble_special=no],)]) +fi + +if test ${hdf5_cv_long_to_ldouble_special} = "yes"; then + AC_DEFINE([LONG_TO_LDOUBLE_SPECIAL], [1], + [Define if your system can convert (unsigned) long to long double values with special algorithm.]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +dnl ---------------------------------------------------------------------- dnl Set the flag to indicate that the machine can accurately convert dnl 'long double' to '(unsigned) long long' values. (This flag should be set for dnl all machines, except for Mac OS 10.4 and SGI IRIX64 6.5. When the bit sequence @@ -3610,6 +3771,7 @@ else AC_MSG_RESULT([no]) fi + dnl ---------------------------------------------------------------------- dnl Set the flag to indicate that the machine can accurately convert dnl '(unsigned) long long' to 'long double' values. (This flag should be set for diff --git a/src/H5config.h.in b/src/H5config.h.in index 3283893..c53ccca 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -435,6 +435,10 @@ values correctly. */ #undef LDOUBLE_TO_LLONG_ACCURATE +/* Define if your system converts long double to (unsigned) long values with + special algorithm. */ +#undef LDOUBLE_TO_LONG_SPECIAL + /* Define if your system can convert long double to unsigned int values correctly. */ #undef LDOUBLE_TO_UINT_ACCURATE @@ -446,6 +450,10 @@ values correctly. */ #undef LLONG_TO_LDOUBLE_CORRECT +/* Define if your system can convert (unsigned) long to long double values + with special algorithm. */ +#undef LONG_TO_LDOUBLE_SPECIAL + /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR diff --git a/test/dt_arith.c b/test/dt_arith.c index 413f326..078242d 100644 --- a/test/dt_arith.c +++ b/test/dt_arith.c @@ -5107,9 +5107,25 @@ run_int_fp_conv(const char *name) nerrors += test_conv_int_fp(name, TEST_NORMAL, H5T_NATIVE_INT, H5T_NATIVE_LDOUBLE); nerrors += test_conv_int_fp(name, TEST_NORMAL, H5T_NATIVE_UINT, H5T_NATIVE_LDOUBLE); #if H5_SIZEOF_LONG!=H5_SIZEOF_INT +#ifndef H5_LONG_TO_LDOUBLE_SPECIAL nerrors += test_conv_int_fp(name, TEST_NORMAL, H5T_NATIVE_LONG, H5T_NATIVE_LDOUBLE); nerrors += test_conv_int_fp(name, TEST_NORMAL, H5T_NATIVE_ULONG, H5T_NATIVE_LDOUBLE); +#else + { + char str[256]; /*string */ + + sprintf(str, "Testing %s %s -> %s conversions", + name, "(unsigned) long", "long double"); + printf("%-70s", str); + SKIPPED(); +#if H5_SIZEOF_LONG_DOUBLE!=0 + HDputs(" Test skipped due to the special algorithm of hardware conversion."); +#else + HDputs(" Test skipped due to disabled long double."); +#endif + } #endif +#endif /* H5_SIZEOF_LONG!=H5_SIZEOF_INT */ #if H5_SIZEOF_LONG_LONG!=H5_SIZEOF_LONG #if H5_LLONG_TO_LDOUBLE_CORRECT nerrors += test_conv_int_fp(name, TEST_NORMAL, H5T_NATIVE_LLONG, H5T_NATIVE_LDOUBLE); @@ -5272,9 +5288,25 @@ run_fp_int_conv(const char *name) } #endif /*H5_LDOUBLE_TO_UINT_ACCURATE*/ #if H5_SIZEOF_LONG!=H5_SIZEOF_INT && H5_SIZEOF_LONG_DOUBLE!=0 +#ifndef H5_LDOUBLE_TO_LONG_SPECIAL nerrors += test_conv_int_fp(name, test_values, H5T_NATIVE_LDOUBLE, H5T_NATIVE_LONG); nerrors += test_conv_int_fp(name, test_values, H5T_NATIVE_LDOUBLE, H5T_NATIVE_ULONG); +#else + { + char str[256]; /*string */ + + sprintf(str, "Testing %s %s -> %s conversions", + name, "long double", "(unsigned) long"); + printf("%-70s", str); + SKIPPED(); +#if H5_SIZEOF_LONG_DOUBLE!=0 + HDputs(" Test skipped due to the special algorithm of hardware conversion."); +#else + HDputs(" Test skipped due to disabled long double."); +#endif + } #endif +#endif /*H5_SIZEOF_LONG!=H5_SIZEOF_INT && H5_SIZEOF_LONG_DOUBLE!=0 */ #if H5_SIZEOF_LONG_LONG!=H5_SIZEOF_LONG && H5_SIZEOF_LONG_DOUBLE!=0 #ifdef H5_LDOUBLE_TO_LLONG_ACCURATE |