diff options
author | ryde <ryde@280ebfd0-de03-0410-8827-d642c229c3f4> | 2003-01-14 22:43:24 +0000 |
---|---|---|
committer | ryde <ryde@280ebfd0-de03-0410-8827-d642c229c3f4> | 2003-01-14 22:43:24 +0000 |
commit | 57892abf1bd25b5d48ed6e5a54a37b74ff64e5c6 (patch) | |
tree | 2508742355a9aa5bab04eafa303ae9c18c19b2f9 /acinclude.m4 | |
parent | 77c4469268caa6bec3327f0da08bfeefc548d03c (diff) | |
download | mpfr-57892abf1bd25b5d48ed6e5a54a37b74ff64e5c6.tar.gz |
(MPFR_C_LONG_DOUBLE_FORMAT): New macro.
(MPFR_CONFIGS): Use it.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@2162 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'acinclude.m4')
-rw-r--r-- | acinclude.m4 | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/acinclude.m4 b/acinclude.m4 index 32614108d..8e152dad1 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -197,4 +197,212 @@ if test "$mpfr_cv_have_huge_val" = "yes"; then AC_DEFINE(HAVE_HUGE_VAL,1,[Define if HUGE_VAL can be used without the need of a specific library.]) fi +MPFR_C_LONG_DOUBLE_FORMAT +]) + + +dnl MPFR_C_LONG_DOUBLE_FORMAT +dnl ------------------------- +dnl Determine the format of a long double. +dnl +dnl The object file is grepped, so as to work when cross compiling. A +dnl start and end sequence is included to avoid false matches, and +dnl allowance is made for the desired data crossing an "od -b" line +dnl boundary. The test number is a small integer so it should appear +dnl exactly, no rounding or truncation etc. +dnl +dnl "od -b" is supported even by Unix V7, and the awk script used doesn't +dnl have functions or anything, so even an "old" awk should suffice. +dnl +dnl The 10-byte IEEE extended format is normally padded to either 12 or 16 +dnl bytes, for alignment purposes. The SVR4 i386 ABI is 12 bytes, or i386 +dnl gcc -m128bit-long-double can select 16 bytes. IA-64 is 16 bytes in +dnl LP64 mode, or 12 bytes in ILP32 mode. The first 10 bytes are the +dnl relevant data, even in IA-64 big-endian mode too. +dnl +dnl Enhancements: +dnl +dnl Could match more formats (IEEE quad, or big endian IEEE), but no need +dnl to worry until there's code wanting to use them. +dnl +dnl Don't want to duplicate the double matching from GMP_C_DOUBLE_FORMAT, +dnl perhaps we should merge with that macro, to match data formats +dnl irrespective of the C type in question. Or perhaps just let the code +dnl use DOUBLE macros when sizeof(double)==sizeof(long double). + +AC_DEFUN(MPFR_C_LONG_DOUBLE_FORMAT, +[AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_AWK]) +AC_CACHE_CHECK([format of `long double' floating point], + mpfr_cv_c_long_double_format, +[mpfr_cv_c_long_double_format=unknown +cat >conftest.c <<\EOF +[ +/* "before" is 16 bytes to ensure there's no padding between it and "x". + We're not expecting any "long double" bigger than 16 bytes or with + alignment requirements stricter than 16 bytes. */ +struct { + char before[16]; + long double x; + char after[8]; +} foo = { + { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\x01', '\x23', '\x45', '\x67', '\x89', '\xAB', '\xCD', '\xEF' }, + -123456789.0, + { '\xFE', '\xDC', '\xBA', '\x98', '\x76', '\x54', '\x32', '\x10' }, +}; +] +EOF +mpfr_compile="$CC $CFLAGS $CPPFLAGS -c conftest.c >&AC_FD_CC 2>&1" +if AC_TRY_EVAL(mpfr_compile); then +cat >conftest.awk <<\EOF +[ +BEGIN { + found = 0 +} + +# got[] holds a sliding window of bytes read the input. got[0] is the most +# recent byte read, and got[31] the oldest byte read, so when looking to +# match some data the indices are "reversed". +# +{ + for (f = 2; f <= NF; f++) + { + # new byte, shift others up + for (i = 31; i >= 0; i--) + got[i+1] = got[i]; + got[0] = $f; + + # end sequence + if (got[7] != "376") continue + if (got[6] != "334") continue + if (got[5] != "272") continue + if (got[4] != "230") continue + if (got[3] != "166") continue + if (got[2] != "124") continue + if (got[1] != "062") continue + if (got[0] != "020") continue + + # start sequence, with 12-byte body + if (got[27] == "001" && \ + got[26] == "043" && \ + got[25] == "105" && \ + got[24] == "147" && \ + got[23] == "211" && \ + got[22] == "253" && \ + got[21] == "315" && \ + got[20] == "357") + { + saw = " (" got[19] \ + " " got[18] \ + " " got[17] \ + " " got[16] \ + " " got[15] \ + " " got[14] \ + " " got[13] \ + " " got[12] \ + " " got[11] \ + " " got[10] \ + " " got[9] \ + " " got[8] ")" + + if (got[19] == "000" && \ + got[18] == "000" && \ + got[17] == "000" && \ + got[16] == "000" && \ + got[15] == "240" && \ + got[14] == "242" && \ + got[13] == "171" && \ + got[12] == "353" && \ + got[11] == "031" && \ + got[10] == "300") + { + print "IEEE extended, little endian" + found = 1 + exit + } + } + + # start sequence, with 16-byte body + if (got[31] == "001" && \ + got[30] == "043" && \ + got[29] == "105" && \ + got[28] == "147" && \ + got[27] == "211" && \ + got[26] == "253" && \ + got[25] == "315" && \ + got[24] == "357") + { + saw = " (" got[23] \ + " " got[22] \ + " " got[21] \ + " " got[20] \ + " " got[19] \ + " " got[18] \ + " " got[17] \ + " " got[16] \ + " " got[15] \ + " " got[14] \ + " " got[13] \ + " " got[12] \ + " " got[11] \ + " " got[10] \ + " " got[9] \ + " " got[8] ")" + + if (got[23] == "000" && \ + got[22] == "000" && \ + got[21] == "000" && \ + got[20] == "000" && \ + got[19] == "240" && \ + got[18] == "242" && \ + got[17] == "171" && \ + got[16] == "353" && \ + got[15] == "031" && \ + got[14] == "300") + { + print "IEEE extended, little endian" + found = 1 + exit + } + } + } +} + +END { + if (! found) + print "unknown", saw +} +] +EOF + mpfr_cv_c_long_double_format=`od -b conftest.$OBJEXT | $AWK -f conftest.awk` + case $mpfr_cv_c_long_double_format in + unknown*) + echo "cannot match anything, conftest.$OBJEXT contains" >&AC_FD_CC + od -b conftest.$OBJEXT >&AC_FD_CC + ;; + esac +else + AC_MSG_WARN([oops, cannot compile test program]) +fi +]) + +AH_VERBATIM([HAVE_LDOUBLE], +[/* Define one of the following to 1 for the format of a `long double'. + If your format is not among these choices, or you don't know what it is, + then leave all undefined. + IEEE_EXT is the 10-byte IEEE extended format. + LITTLE or BIG is the endianness. */ +#undef HAVE_LDOUBLE_IEEE_EXT_LITTLE]) + +case $mpfr_cv_c_long_double_format in + "IEEE extended, little endian") + AC_DEFINE(HAVE_LDOUBLE_IEEE_EXT_LITTLE, 1) + ;; + unknown*) + ;; + *) + AC_MSG_WARN([oops, unrecognised float format: $mpfr_cv_c_long_double_format]) + ;; +esac ]) |