1# signbit.m4 serial 19
2dnl Copyright (C) 2007-2020 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7AC_DEFUN([gl_SIGNBIT],
8[
9  AC_REQUIRE([gl_MATH_H_DEFAULTS])
10  AC_REQUIRE([AC_CANONICAL_HOST])
11  AC_CACHE_CHECK([for signbit macro], [gl_cv_func_signbit],
12    [
13      AC_RUN_IFELSE(
14        [AC_LANG_SOURCE([[
15#include <math.h>
16/* If signbit is defined as a function, don't use it, since calling it for
17   'float' or 'long double' arguments would involve conversions.
18   If signbit is not declared at all but exists as a library function, don't
19   use it, since the prototype may not match.
20   If signbit is not declared at all but exists as a compiler built-in, don't
21   use it, since it's preferable to use __builtin_signbit* (no warnings,
22   no conversions).  */
23#ifndef signbit
24# error "signbit should be a macro"
25#endif
26#include <string.h>
27]gl_SIGNBIT_TEST_PROGRAM
28])],
29        [gl_cv_func_signbit=yes],
30        [gl_cv_func_signbit=no],
31        [case "$host_os" in
32                          # Guess yes on glibc systems.
33           *-gnu* | gnu*) gl_cv_func_signbit="guessing yes" ;;
34                          # Guess yes on musl systems.
35           *-musl*)       gl_cv_func_signbit="guessing yes" ;;
36                          # Guess yes on native Windows.
37           mingw*)        gl_cv_func_signbit="guessing yes" ;;
38                          # If we don't know, obey --enable-cross-guesses.
39           *)             gl_cv_func_signbit="$gl_cross_guess_normal" ;;
40         esac
41        ])
42    ])
43  dnl GCC 4.0 and newer provides three built-ins for signbit.
44  dnl They can be used without warnings, also in C++, regardless of <math.h>.
45  dnl But they may expand to calls to functions, which may or may not be in
46  dnl libc.
47  AC_CACHE_CHECK([for signbit compiler built-ins], [gl_cv_func_signbit_gcc],
48    [
49      AC_RUN_IFELSE(
50        [AC_LANG_SOURCE([[
51#if __GNUC__ >= 4
52# define signbit(x) \
53   (sizeof (x) == sizeof (long double) ? __builtin_signbitl (x) : \
54    sizeof (x) == sizeof (double) ? __builtin_signbit (x) : \
55    __builtin_signbitf (x))
56#else
57# error "signbit should be three compiler built-ins"
58#endif
59#include <string.h>
60]gl_SIGNBIT_TEST_PROGRAM
61])],
62        [gl_cv_func_signbit_gcc=yes],
63        [gl_cv_func_signbit_gcc=no],
64        [case "$host_os" in
65                          # Guess yes on glibc systems.
66           *-gnu* | gnu*) gl_cv_func_signbit_gcc="guessing yes" ;;
67                          # Guess yes on musl systems.
68           *-musl*)       gl_cv_func_signbit_gcc="guessing yes" ;;
69                          # Guess yes on mingw, no on MSVC.
70           mingw*)        if test -n "$GCC"; then
71                            gl_cv_func_signbit_gcc="guessing yes"
72                          else
73                            gl_cv_func_signbit_gcc="guessing no"
74                          fi
75                          ;;
76                          # If we don't know, obey --enable-cross-guesses.
77           *)             gl_cv_func_signbit_gcc="$gl_cross_guess_normal" ;;
78         esac
79        ])
80    ])
81  dnl Use the compiler built-ins whenever possible, because they are more
82  dnl efficient than the system library functions (if they exist).
83  case "$gl_cv_func_signbit_gcc" in
84    *yes)
85      REPLACE_SIGNBIT_USING_GCC=1
86      ;;
87    *)
88      case "$gl_cv_func_signbit" in
89        *yes) ;;
90        *)
91          dnl REPLACE_SIGNBIT=1 makes sure the signbit[fdl] functions get built.
92          REPLACE_SIGNBIT=1
93          ;;
94      esac
95      ;;
96  esac
97  dnl On Solaris 10, with CC in C++ mode, signbit is not available although
98  dnl is with cc in C mode. This cannot be worked around by defining
99  dnl _XOPEN_SOURCE=600, because the latter does not work in C++ mode on
100  dnl Solaris 11.0. Therefore use the replacement functions on Solaris.
101  case "$host_os" in
102    solaris*)
103      REPLACE_SIGNBIT=1
104      ;;
105  esac
106  if test $REPLACE_SIGNBIT = 1; then
107    gl_FLOAT_SIGN_LOCATION
108    gl_DOUBLE_SIGN_LOCATION
109    gl_LONG_DOUBLE_SIGN_LOCATION
110    if test "$gl_cv_cc_float_signbit" = unknown; then
111      dnl Test whether copysignf() is declared.
112      AC_CHECK_DECLS([copysignf], , , [[#include <math.h>]])
113      if test "$ac_cv_have_decl_copysignf" = yes; then
114        dnl Test whether copysignf() can be used without libm.
115        AC_CACHE_CHECK([whether copysignf can be used without linking with libm],
116          [gl_cv_func_copysignf_no_libm],
117          [
118            AC_LINK_IFELSE(
119              [AC_LANG_PROGRAM(
120                 [[#include <math.h>
121                   float x, y;]],
122                 [[return copysignf (x, y) < 0;]])],
123              [gl_cv_func_copysignf_no_libm=yes],
124              [gl_cv_func_copysignf_no_libm=no])
125          ])
126        if test $gl_cv_func_copysignf_no_libm = yes; then
127          AC_DEFINE([HAVE_COPYSIGNF_IN_LIBC], [1],
128            [Define if the copysignf function is declared in <math.h> and available in libc.])
129        fi
130      fi
131    fi
132    if test "$gl_cv_cc_double_signbit" = unknown; then
133      dnl Test whether copysign() is declared.
134      AC_CHECK_DECLS([copysign], , , [[#include <math.h>]])
135      if test "$ac_cv_have_decl_copysign" = yes; then
136        dnl Test whether copysign() can be used without libm.
137        AC_CACHE_CHECK([whether copysign can be used without linking with libm],
138          [gl_cv_func_copysign_no_libm],
139          [
140            AC_LINK_IFELSE(
141              [AC_LANG_PROGRAM(
142                 [[#include <math.h>
143                   double x, y;]],
144                 [[return copysign (x, y) < 0;]])],
145              [gl_cv_func_copysign_no_libm=yes],
146              [gl_cv_func_copysign_no_libm=no])
147          ])
148        if test $gl_cv_func_copysign_no_libm = yes; then
149          AC_DEFINE([HAVE_COPYSIGN_IN_LIBC], [1],
150            [Define if the copysign function is declared in <math.h> and available in libc.])
151        fi
152      fi
153    fi
154    if test "$gl_cv_cc_long_double_signbit" = unknown; then
155      dnl Test whether copysignl() is declared.
156      AC_CHECK_DECLS([copysignl], , , [[#include <math.h>]])
157      if test "$ac_cv_have_decl_copysignl" = yes; then
158        dnl Test whether copysignl() can be used without libm.
159        AC_CACHE_CHECK([whether copysignl can be used without linking with libm],
160          [gl_cv_func_copysignl_no_libm],
161          [
162            AC_LINK_IFELSE(
163              [AC_LANG_PROGRAM(
164                 [[#include <math.h>
165                   long double x, y;]],
166                 [[return copysignl (x, y) < 0;]])],
167              [gl_cv_func_copysignl_no_libm=yes],
168              [gl_cv_func_copysignl_no_libm=no])
169          ])
170        if test $gl_cv_func_copysignl_no_libm = yes; then
171          AC_DEFINE([HAVE_COPYSIGNL_IN_LIBC], [1],
172            [Define if the copysignl function is declared in <math.h> and available in libc.])
173        fi
174      fi
175    fi
176  fi
177])
178
179AC_DEFUN([gl_SIGNBIT_TEST_PROGRAM], [[
180/* Global variables.
181   Needed because GCC 4 constant-folds __builtin_signbitl (literal)
182   but cannot constant-fold            __builtin_signbitl (variable).  */
183float vf;
184double vd;
185long double vl;
186int main ()
187{
188/* HP cc on HP-UX 10.20 has a bug with the constant expression -0.0.
189   So we use -p0f and -p0d instead.  */
190float p0f = 0.0f;
191float m0f = -p0f;
192double p0d = 0.0;
193double m0d = -p0d;
194/* On HP-UX 10.20, negating 0.0L does not yield -0.0L.
195   So we use another constant expression instead.
196   But that expression does not work on other platforms, such as when
197   cross-compiling to PowerPC on Mac OS X 10.5.  */
198long double p0l = 0.0L;
199#if defined __hpux || defined __sgi
200long double m0l = -LDBL_MIN * LDBL_MIN;
201#else
202long double m0l = -p0l;
203#endif
204  int result = 0;
205  if (signbit (vf)) /* link check */
206    vf++;
207  {
208    float plus_inf = 1.0f / p0f;
209    float minus_inf = -1.0f / p0f;
210    if (!(!signbit (255.0f)
211          && signbit (-255.0f)
212          && !signbit (p0f)
213          && (memcmp (&m0f, &p0f, sizeof (float)) == 0 || signbit (m0f))
214          && !signbit (plus_inf)
215          && signbit (minus_inf)))
216      result |= 1;
217  }
218  if (signbit (vd)) /* link check */
219    vd++;
220  {
221    double plus_inf = 1.0 / p0d;
222    double minus_inf = -1.0 / p0d;
223    if (!(!signbit (255.0)
224          && signbit (-255.0)
225          && !signbit (p0d)
226          && (memcmp (&m0d, &p0d, sizeof (double)) == 0 || signbit (m0d))
227          && !signbit (plus_inf)
228          && signbit (minus_inf)))
229      result |= 2;
230  }
231  if (signbit (vl)) /* link check */
232    vl++;
233  {
234    long double plus_inf = 1.0L / p0l;
235    long double minus_inf = -1.0L / p0l;
236    if (signbit (255.0L))
237      result |= 4;
238    if (!signbit (-255.0L))
239      result |= 4;
240    if (signbit (p0l))
241      result |= 8;
242    if (!(memcmp (&m0l, &p0l, sizeof (long double)) == 0 || signbit (m0l)))
243      result |= 16;
244    if (signbit (plus_inf))
245      result |= 32;
246    if (!signbit (minus_inf))
247      result |= 64;
248  }
249  return result;
250}
251]])
252
253AC_DEFUN([gl_FLOAT_SIGN_LOCATION],
254[
255  gl_FLOATTYPE_SIGN_LOCATION([float], [gl_cv_cc_float_signbit], [f], [FLT])
256])
257
258AC_DEFUN([gl_DOUBLE_SIGN_LOCATION],
259[
260  gl_FLOATTYPE_SIGN_LOCATION([double], [gl_cv_cc_double_signbit], [], [DBL])
261])
262
263AC_DEFUN([gl_LONG_DOUBLE_SIGN_LOCATION],
264[
265  gl_FLOATTYPE_SIGN_LOCATION([long double], [gl_cv_cc_long_double_signbit], [L], [LDBL])
266])
267
268AC_DEFUN([gl_FLOATTYPE_SIGN_LOCATION],
269[
270  AC_CACHE_CHECK([where to find the sign bit in a '$1'],
271    [$2],
272    [
273      AC_RUN_IFELSE(
274        [AC_LANG_SOURCE([[
275#include <stddef.h>
276#include <stdio.h>
277#define NWORDS \
278  ((sizeof ($1) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
279typedef union { $1 value; unsigned int word[NWORDS]; }
280        memory_float;
281static memory_float plus = { 1.0$3 };
282static memory_float minus = { -1.0$3 };
283int main ()
284{
285  size_t j, k, i;
286  unsigned int m;
287  FILE *fp = fopen ("conftest.out", "w");
288  if (fp == NULL)
289    return 1;
290  /* Find the different bit.  */
291  k = 0; m = 0;
292  for (j = 0; j < NWORDS; j++)
293    {
294      unsigned int x = plus.word[j] ^ minus.word[j];
295      if ((x & (x - 1)) || (x && m))
296        {
297          /* More than one bit difference.  */
298          fprintf (fp, "unknown");
299          fclose (fp);
300          return 2;
301        }
302      if (x)
303        {
304          k = j;
305          m = x;
306        }
307    }
308  if (m == 0)
309    {
310      /* No difference.  */
311      fprintf (fp, "unknown");
312      fclose (fp);
313      return 3;
314    }
315  /* Now m = plus.word[k] ^ ~minus.word[k].  */
316  if (plus.word[k] & ~minus.word[k])
317    {
318      /* Oh? The sign bit is set in the positive and cleared in the negative
319         numbers?  */
320      fprintf (fp, "unknown");
321      fclose (fp);
322      return 4;
323    }
324  for (i = 0; ; i++)
325    if ((m >> i) & 1)
326      break;
327  fprintf (fp, "word %d bit %d", (int) k, (int) i);
328  if (fclose (fp) != 0)
329    return 5;
330  return 0;
331}
332        ]])],
333        [$2=`cat conftest.out`],
334        [$2="unknown"],
335        [
336          dnl When cross-compiling, we don't know. It depends on the
337          dnl ABI and compiler version. There are too many cases.
338          $2="unknown"
339        ])
340      rm -f conftest.out
341    ])
342  case "$]$2[" in
343    word*bit*)
344      word=`echo "$]$2[" | sed -e 's/word //' -e 's/ bit.*//'`
345      bit=`echo "$]$2[" | sed -e 's/word.*bit //'`
346      AC_DEFINE_UNQUOTED([$4][_SIGNBIT_WORD], [$word],
347        [Define as the word index where to find the sign of '$1'.])
348      AC_DEFINE_UNQUOTED([$4][_SIGNBIT_BIT], [$bit],
349        [Define as the bit index in the word where to find the sign of '$1'.])
350      ;;
351  esac
352])
353
354# Expands to code that defines a function signbitf(float).
355# It extracts the sign bit of a non-NaN value.
356AC_DEFUN([gl_FLOAT_SIGNBIT_CODE],
357[
358  gl_FLOATTYPE_SIGNBIT_CODE([float], [f], [f])
359])
360
361# Expands to code that defines a function signbitd(double).
362# It extracts the sign bit of a non-NaN value.
363AC_DEFUN([gl_DOUBLE_SIGNBIT_CODE],
364[
365  gl_FLOATTYPE_SIGNBIT_CODE([double], [d], [])
366])
367
368# Expands to code that defines a function signbitl(long double).
369# It extracts the sign bit of a non-NaN value.
370AC_DEFUN([gl_LONG_DOUBLE_SIGNBIT_CODE],
371[
372  gl_FLOATTYPE_SIGNBIT_CODE([long double], [l], [L])
373])
374
375AC_DEFUN([gl_FLOATTYPE_SIGNBIT_CODE],
376[[
377static int
378signbit$2 ($1 value)
379{
380  typedef union { $1 f; unsigned char b[sizeof ($1)]; } float_union;
381  static float_union plus_one = { 1.0$3 };   /* unused bits are zero here */
382  static float_union minus_one = { -1.0$3 }; /* unused bits are zero here */
383  /* Compute the sign bit mask as the XOR of plus_one and minus_one.  */
384  float_union u;
385  unsigned int i;
386  u.f = value;
387  for (i = 0; i < sizeof ($1); i++)
388    if (u.b[i] & (plus_one.b[i] ^ minus_one.b[i]))
389      return 1;
390  return 0;
391}
392]])
393