f21d38485e4454f1e3db71d7c8a73765760b7612
[gnulib.git] / m4 / isnand.m4
1 # isnand.m4 serial 3
2 dnl Copyright (C) 2007-2008 Free Software Foundation, Inc.
3 dnl This file is free software; the Free Software Foundation
4 dnl gives unlimited permission to copy and/or distribute it,
5 dnl with or without modifications, as long as this notice is preserved.
6
7 dnl Check how to get or define isnand().
8 AC_DEFUN([gl_FUNC_ISNAND],
9 [
10   ISNAND_LIBM=
11   gl_HAVE_ISNAND_NO_LIBM
12   if test $gl_cv_func_isnand_no_libm = no; then
13     gl_HAVE_ISNAND_IN_LIBM
14     if test $gl_cv_func_isnand_in_libm = yes; then
15       ISNAND_LIBM=-lm
16     fi
17   fi
18   dnl The variable gl_func_isnand set here is used by isnan.m4.
19   if test $gl_cv_func_isnand_no_libm = yes \
20      || test $gl_cv_func_isnand_in_libm = yes; then
21     gl_func_isnand=yes
22     AC_DEFINE([HAVE_ISNAND], 1,
23       [Define if the isnan(double) function is available.])
24   else
25     gl_func_isnand=no
26     gl_BUILD_ISNAND
27   fi
28   AC_SUBST([ISNAND_LIBM])
29 ])
30
31 dnl Check how to get or define isnand() without linking with libm.
32
33 AC_DEFUN([gl_FUNC_ISNAND_NO_LIBM],
34 [
35   gl_HAVE_ISNAND_NO_LIBM
36   if test $gl_cv_func_isnand_no_libm = yes; then
37     AC_DEFINE([HAVE_ISNAND_IN_LIBC], 1,
38       [Define if the isnan(double) function is available in libc.])
39   else
40     gl_BUILD_ISNAND
41   fi
42 ])
43
44 dnl Pull in replacement isnand definition. It does not need -lm.
45 AC_DEFUN([gl_BUILD_ISNAND],
46 [
47   AC_LIBOBJ([isnand])
48   gl_DOUBLE_EXPONENT_LOCATION
49 ])
50
51 dnl Test whether isnand() can be used with libm.
52
53 AC_DEFUN([gl_HAVE_ISNAND_IN_LIBM],
54 [
55   AC_CACHE_CHECK([whether isnan(double) can be used with libm],
56     [gl_cv_func_isnand_in_libm],
57     [
58       save_LIBS="$LIBS"
59       LIBS="$LIBS -lm"
60       AC_TRY_LINK([#include <math.h>
61                    #if __GNUC__ >= 4
62                    # undef isnand
63                    # define isnand(x) __builtin_isnand ((double)(x))
64                    #elif defined isnan
65                    # undef isnand
66                    # define isnand(x) isnan ((double)(x))
67                    #endif
68                    double x;],
69                   [return isnand (x);],
70         [gl_cv_func_isnand_in_libm=yes],
71         [gl_cv_func_isnand_in_libm=no])
72       LIBS="$save_LIBS"
73     ])
74 ])
75
76 AC_DEFUN([gl_HAVE_ISNAND_NO_LIBM],
77 [
78   AC_CACHE_CHECK([whether isnan(double) can be used without linking with libm],
79     [gl_cv_func_isnand_no_libm],
80     [
81       AC_TRY_LINK([#include <math.h>
82                    #if __GNUC__ >= 4
83                    # undef isnand
84                    # define isnand(x) __builtin_isnan ((double)(x))
85                    #else
86                    # undef isnand
87                    # define isnand(x) isnan ((double)(x))
88                    #endif
89                    double x;],
90                   [return isnand (x);],
91         [gl_cv_func_isnand_no_libm=yes],
92         [gl_cv_func_isnand_no_libm=no])
93     ])
94 ])
95
96 AC_DEFUN([gl_DOUBLE_EXPONENT_LOCATION],
97 [
98   AC_CACHE_CHECK([where to find the exponent in a 'double'],
99     [gl_cv_cc_double_expbit0],
100     [
101       AC_TRY_RUN([
102 #include <float.h>
103 #include <stddef.h>
104 #include <stdio.h>
105 #include <string.h>
106 #define NWORDS \
107   ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
108 typedef union { double value; unsigned int word[NWORDS]; } memory_double;
109 static unsigned int ored_words[NWORDS];
110 static unsigned int anded_words[NWORDS];
111 static void add_to_ored_words (double x)
112 {
113   memory_double m;
114   size_t i;
115   /* Clear it first, in case sizeof (double) < sizeof (memory_double).  */
116   memset (&m, 0, sizeof (memory_double));
117   m.value = x;
118   for (i = 0; i < NWORDS; i++)
119     {
120       ored_words[i] |= m.word[i];
121       anded_words[i] &= m.word[i];
122     }
123 }
124 int main ()
125 {
126   size_t j;
127   FILE *fp = fopen ("conftest.out", "w");
128   if (fp == NULL)
129     return 1;
130   for (j = 0; j < NWORDS; j++)
131     anded_words[j] = ~ (unsigned int) 0;
132   add_to_ored_words (0.25);
133   add_to_ored_words (0.5);
134   add_to_ored_words (1.0);
135   add_to_ored_words (2.0);
136   add_to_ored_words (4.0);
137   /* Remove bits that are common (e.g. if representation of the first mantissa
138      bit is explicit).  */
139   for (j = 0; j < NWORDS; j++)
140     ored_words[j] &= ~anded_words[j];
141   /* Now find the nonzero word.  */
142   for (j = 0; j < NWORDS; j++)
143     if (ored_words[j] != 0)
144       break;
145   if (j < NWORDS)
146     {
147       size_t i;
148       for (i = j + 1; i < NWORDS; i++)
149         if (ored_words[i] != 0)
150           {
151             fprintf (fp, "unknown");
152             return (fclose (fp) != 0);
153           }
154       for (i = 0; ; i++)
155         if ((ored_words[j] >> i) & 1)
156           {
157             fprintf (fp, "word %d bit %d", (int) j, (int) i);
158             return (fclose (fp) != 0);
159           }
160     }
161   fprintf (fp, "unknown");
162   return (fclose (fp) != 0);
163 }
164         ],
165         [gl_cv_cc_double_expbit0=`cat conftest.out`],
166         [gl_cv_cc_double_expbit0="unknown"],
167         [
168           dnl On ARM, there are two 'double' floating-point formats, used by
169           dnl different sets of instructions: The older FPA instructions assume
170           dnl that they are stored in big-endian word order, while the words
171           dnl (like integer types) are stored in little-endian byte order.
172           dnl The newer VFP instructions assume little-endian order consistenly.
173           AC_EGREP_CPP([mixed_endianness], [
174 #if defined arm || defined __arm || defined __arm__
175   mixed_endianness
176 #endif
177             ],
178             [gl_cv_cc_double_expbit0="unknown"],
179             [
180               pushdef([AC_MSG_CHECKING],[:])dnl
181               pushdef([AC_MSG_RESULT],[:])dnl
182               pushdef([AC_MSG_RESULT_UNQUOTED],[:])dnl
183               AC_C_BIGENDIAN(
184                 [gl_cv_cc_double_expbit0="word 0 bit 20"],
185                 [gl_cv_cc_double_expbit0="word 1 bit 20"],
186                 [gl_cv_cc_double_expbit0="unknown"])
187               popdef([AC_MSG_RESULT_UNQUOTED])dnl
188               popdef([AC_MSG_RESULT])dnl
189               popdef([AC_MSG_CHECKING])dnl
190             ])
191         ])
192       rm -f conftest.out
193     ])
194   case "$gl_cv_cc_double_expbit0" in
195     word*bit*)
196       word=`echo "$gl_cv_cc_double_expbit0" | sed -e 's/word //' -e 's/ bit.*//'`
197       bit=`echo "$gl_cv_cc_double_expbit0" | sed -e 's/word.*bit //'`
198       AC_DEFINE_UNQUOTED([DBL_EXPBIT0_WORD], [$word],
199         [Define as the word index where to find the exponent of 'double'.])
200       AC_DEFINE_UNQUOTED([DBL_EXPBIT0_BIT], [$bit],
201         [Define as the bit index in the word where to find bit 0 of the exponent of 'double'.])
202       ;;
203   esac
204 ])