From a1fbeb3e4f08c2f612d551a3ad2c53a3737a5e6c Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Thu, 28 Mar 2019 17:55:59 +0800 Subject: [PATCH 1/4] build: Improve tests for frexpl() and ldexpl() The test programs for those in the Meson build files will not work for Visual Studio prior to 2013 (whereas the rest of the code does). Improve the tests for these by: -Adding a test to see whether we can re-define a prototype for these functions, using cc.compiles(). If so, set HAVE_DECL_xxxx to be 0, otherwise set HAVE_DECL_xxxx to be 1. Also, for glib/gnulib/frexpl.c, don't undefine frexpl on Visual Studio, otherwise we will not be able to compile/link it on Visual Studio compilers. --- glib/gnulib/frexpl.c | 2 ++ glib/gnulib/gl_cv_func_frexpl_works/meson.build | 12 ++++++++++++ glib/gnulib/gl_cv_func_ldexpl_works/meson.build | 12 ++++++++++++ glib/gnulib/meson.build | 2 ++ 4 files changed, 28 insertions(+) diff --git a/glib/gnulib/frexpl.c b/glib/gnulib/frexpl.c index 5736dc848..cd6a81c77 100644 --- a/glib/gnulib/frexpl.c +++ b/glib/gnulib/frexpl.c @@ -14,6 +14,8 @@ long double rpl_frexpl (long double x, int *expptr) return x; else if (isinf (x)) return x; +#ifndef _MSC_VER #undef frexpl +#endif return frexpl (x, expptr); } diff --git a/glib/gnulib/gl_cv_func_frexpl_works/meson.build b/glib/gnulib/gl_cv_func_frexpl_works/meson.build index c37b741db..303ec63d7 100644 --- a/glib/gnulib/gl_cv_func_frexpl_works/meson.build +++ b/glib/gnulib/gl_cv_func_frexpl_works/meson.build @@ -29,7 +29,11 @@ extern #ifdef __cplusplus "C" #endif + +#if !defined (_MSC_VER) || defined (TEST_FREXPL_DECL) long double frexpl (long double, int *); +#endif + int main() { int result = 0; @@ -128,3 +132,11 @@ else gl_cv_func_frexpl_broken_beyond_repair = false endif endif + +frexpl_test_decl = ''' +#define TEST_FREXPL_DECL 1 +''' + frexpl_test + +build_result = cc.compiles(frexpl_test_decl, + name : 'frexpl prototype can be re-listed') +gl_cv_func_frexpl_decl = build_result diff --git a/glib/gnulib/gl_cv_func_ldexpl_works/meson.build b/glib/gnulib/gl_cv_func_ldexpl_works/meson.build index dc83675ed..ae176cb8e 100644 --- a/glib/gnulib/gl_cv_func_ldexpl_works/meson.build +++ b/glib/gnulib/gl_cv_func_ldexpl_works/meson.build @@ -9,7 +9,11 @@ extern #ifdef __cplusplus "C" #endif + +#if !defined (_MSC_VER) || defined (TEST_LDEXPL_DECL) long double ldexpl (long double, int); +#endif + int main() { int result = 0; @@ -43,3 +47,11 @@ else gl_cv_func_ldexpl_works = true endif endif + +ldexpl_test_decl = ''' +#define TEST_LDEXPL_DECL 1 +''' + ldexpl_test + +build_result = cc.compiles(ldexpl_test_decl, + name : 'ldexpl prototype can be re-listed') +gl_cv_func_ldexpl_decl = build_result diff --git a/glib/gnulib/meson.build b/glib/gnulib/meson.build index 60499d9b7..2d369a6ef 100644 --- a/glib/gnulib/meson.build +++ b/glib/gnulib/meson.build @@ -282,6 +282,7 @@ endif math_h_config.set ('REPLACE_FREXP', gl_cv_func_frexp_works ? 0 : 1) math_h_config.set ('REPLACE_FREXPL', gl_cv_func_frexpl_works ? 0 : 1) +math_h_config.set ('HAVE_DECL_FREXPL', gl_cv_func_frexpl_decl ? 0 : 1) math_h_config.set ('REPLACE_ITOLD', 0) math_h_config.set ('REPLACE_HUGE_VAL', 0) @@ -293,6 +294,7 @@ else gl_cv_func_ldexpl_works = false endif math_h_config.set ('REPLACE_LDEXPL', gl_cv_func_ldexpl_works ? 0 : 1) +math_h_config.set ('HAVE_DECL_LDEXPL', gl_cv_func_ldexpl_decl ? 0 : 1) math_h = configure_file (input: 'gnulib_math.h.in', output: 'gnulib_math.h', From b532b9cecf977b6e42e1c63503a800495fae1e0c Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Thu, 28 Mar 2019 18:27:33 +0800 Subject: [PATCH 2/4] build: Check for more math.h functions in gnulib There are now C99 functions that the printf items want to use that may not be necessarily supported by the math.h that is shipped by the compiler, such as signbit(), isinf(), isnan() and isfinite() and their double, long and float counterparts. This checks for whether these functions are provided by the math.h shipped by the compiler, and builds the gnulib implementations of them if they cannot be found. Currently no attempt is made to check whether these, if available from the compiler's math.h, are compliant with the specs. --- glib/gnulib/isinf.c | 30 +++++++++++++++++ glib/gnulib/isnanf-nolibm.h | 40 +++++++++++++++++++++++ glib/gnulib/isnanf.c | 20 ++++++++++++ glib/gnulib/meson.build | 35 +++++++++++++++++--- glib/gnulib/signbitd.c | 64 +++++++++++++++++++++++++++++++++++++ glib/gnulib/signbitf.c | 64 +++++++++++++++++++++++++++++++++++++ glib/gnulib/signbitl.c | 64 +++++++++++++++++++++++++++++++++++++ 7 files changed, 312 insertions(+), 5 deletions(-) create mode 100644 glib/gnulib/isinf.c create mode 100644 glib/gnulib/isnanf-nolibm.h create mode 100644 glib/gnulib/isnanf.c create mode 100644 glib/gnulib/signbitd.c create mode 100644 glib/gnulib/signbitf.c create mode 100644 glib/gnulib/signbitl.c diff --git a/glib/gnulib/isinf.c b/glib/gnulib/isinf.c new file mode 100644 index 000000000..e7b44b98d --- /dev/null +++ b/glib/gnulib/isinf.c @@ -0,0 +1,30 @@ +#ifndef _MSC_VER +#error "This implementation is currently supported for Visual Studio only!" +#endif + +#include "config.h" +#include +#include +#include + +int +gl_isinff (float x) +{ +#if defined (_WIN64) && (defined (_M_X64) || defined (_M_AMD64)) + return !_finitef (x); +#else + return !_finite (x); +#endif +} + +int +gl_isinfd (double x) +{ + return !_finite (x); +} + +int +gl_isinfl (long double x) +{ + return gl_isinfd (x); +} \ No newline at end of file diff --git a/glib/gnulib/isnanf-nolibm.h b/glib/gnulib/isnanf-nolibm.h new file mode 100644 index 000000000..47c52f7f3 --- /dev/null +++ b/glib/gnulib/isnanf-nolibm.h @@ -0,0 +1,40 @@ +/* Test for NaN that does not need libm. + Copyright (C) 2007-2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General PublicLicense as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General PublicLicense for more details. + + You should have received a copy of the GNU Lesser General PublicLicense + along with this program. If not, see . */ + +#if HAVE_ISNANF_IN_LIBC +/* Get declaration of isnan macro or (older) isnanf function. */ +# include +# if __GNUC__ >= 4 + /* GCC 4.0 and newer provides three built-ins for isnan. */ +# undef isnanf +# define isnanf(x) __builtin_isnanf ((float)(x)) +# elif defined isnan +# undef isnanf +# define isnanf(x) isnan ((float)(x)) +# else + /* Get declaration of isnanf(), if not declared in . */ +# if defined __sgi + /* We can't include , because it conflicts with our definition of + isnand. Therefore declare isnanf separately. */ +extern int isnanf (float x); +# endif +# endif +#else +/* Test whether X is a NaN. */ +# undef isnanf +# define isnanf rpl_isnanf +extern int isnanf (float x); +#endif diff --git a/glib/gnulib/isnanf.c b/glib/gnulib/isnanf.c new file mode 100644 index 000000000..8651733a1 --- /dev/null +++ b/glib/gnulib/isnanf.c @@ -0,0 +1,20 @@ +/* Test for NaN that does not need libm. + Copyright (C) 2007, 2009-2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General PublicLicense as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General PublicLicense for more details. + + You should have received a copy of the GNU Lesser General PublicLicense + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2007. */ + +#define USE_FLOAT +#include "isnan.c" diff --git a/glib/gnulib/meson.build b/glib/gnulib/meson.build index 2d369a6ef..af697f29c 100644 --- a/glib/gnulib/meson.build +++ b/glib/gnulib/meson.build @@ -51,10 +51,6 @@ unneeded_funcs = [ 'ILOGB', 'ILOGBF', 'ILOGBL', - 'ISFINITE', - 'ISINF', - 'ISNAN', - 'ISNANF', 'LDEXPF', 'LOG', 'LOG10', @@ -84,7 +80,6 @@ unneeded_funcs = [ 'ROUND', 'ROUNDF', 'ROUNDL', - 'SIGNBIT', 'SINF', 'SINHF', 'SINL', @@ -110,9 +105,14 @@ endforeach needed_funcs = [ 'FREXP', 'FREXPL', + 'ISFINITE', + 'ISINF', + 'ISNAN', 'ISNAND', + 'ISNANF', 'ISNANL', 'LDEXPL', + 'SIGNBIT', ] foreach f : needed_funcs @@ -296,6 +296,29 @@ endif math_h_config.set ('REPLACE_LDEXPL', gl_cv_func_ldexpl_works ? 0 : 1) math_h_config.set ('HAVE_DECL_LDEXPL', gl_cv_func_ldexpl_decl ? 0 : 1) +inf_tmpl = '''#include + double x; + int main () {return @0@ (x);} + ''' + +other_needed_math_sources = [] +# Some compilers may not have isfinite, isinf available +foreach f: ['isfinite', 'isinf', 'isnan', 'isnanf', 'signbit'] + links = cc.links (inf_tmpl.format('@0@'.format(f)), + dependencies : [libm]) + math_h_config.set ('HAVE_@0@'.format(f.to_upper()), links ? 1 : 0) + math_h_config.set ('HAVE_@0@_IN_LIBC'.format(f.to_upper()), links ? 1 : 0) + math_h_config.set ('REPLACE_@0@'.format(f.to_upper()), links ? 0 : 1) + set_variable ('have_@0@'.format(f), links) + if not links + if f == 'signbit' + other_needed_math_sources += [ 'signbitd.c', 'signbitf.c', 'signbitl.c' ] + elif f != 'isfinite' and f != 'isnan' + other_needed_math_sources += [ '@0@.c'.format(f) ] + endif + endif +endforeach + math_h = configure_file (input: 'gnulib_math.h.in', output: 'gnulib_math.h', configuration: math_h_config) @@ -309,6 +332,8 @@ if not gl_cv_func_frexpl_works gnulib_sources += ['frexpl.c'] endif +gnulib_sources += other_needed_math_sources + gnulib_lib = static_library('gnulib', gnulib_sources, dependencies : [libm], include_directories : [configinc, glibinc, include_directories ('.')], diff --git a/glib/gnulib/signbitd.c b/glib/gnulib/signbitd.c new file mode 100644 index 000000000..7b20f9b2c --- /dev/null +++ b/glib/gnulib/signbitd.c @@ -0,0 +1,64 @@ +/* signbit() macro: Determine the sign bit of a floating-point number. + Copyright (C) 2007-2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General PublicLicense as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General PublicLicense for more details. + + You should have received a copy of the GNU Lesser General PublicLicense + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include + +#include +#include "isnand-nolibm.h" +#include "float+.h" + +#ifdef gl_signbitd_OPTIMIZED_MACRO +# undef gl_signbitd +#endif + +int +gl_signbitd (double arg) +{ +#if defined DBL_SIGNBIT_WORD && defined DBL_SIGNBIT_BIT + /* The use of a union to extract the bits of the representation of a + 'long double' is safe in practice, despite of the "aliasing rules" of + C99, because the GCC docs say + "Even with '-fstrict-aliasing', type-punning is allowed, provided the + memory is accessed through the union type." + and similarly for other compilers. */ +# define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + union { double value; unsigned int word[NWORDS]; } m; + m.value = arg; + return (m.word[DBL_SIGNBIT_WORD] >> DBL_SIGNBIT_BIT) & 1; +#elif HAVE_COPYSIGN_IN_LIBC + return copysign (1.0, arg) < 0; +#else + /* This does not do the right thing for NaN, but this is irrelevant for + most use cases. */ + if (isnand (arg)) + return 0; + if (arg < 0.0) + return 1; + else if (arg == 0.0) + { + /* Distinguish 0.0 and -0.0. */ + static double plus_zero = 0.0; + double arg_mem = arg; + return (memcmp (&plus_zero, &arg_mem, SIZEOF_DBL) != 0); + } + else + return 0; +#endif +} diff --git a/glib/gnulib/signbitf.c b/glib/gnulib/signbitf.c new file mode 100644 index 000000000..57e6ef4c7 --- /dev/null +++ b/glib/gnulib/signbitf.c @@ -0,0 +1,64 @@ +/* signbit() macro: Determine the sign bit of a floating-point number. + Copyright (C) 2007, 2009-2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General PublicLicense as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General PublicLicense for more details. + + You should have received a copy of the GNU Lesser General PublicLicense + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include + +#include +#include "isnanf-nolibm.h" +#include "float+.h" + +#ifdef gl_signbitf_OPTIMIZED_MACRO +# undef gl_signbitf +#endif + +int +gl_signbitf (float arg) +{ +#if defined FLT_SIGNBIT_WORD && defined FLT_SIGNBIT_BIT + /* The use of a union to extract the bits of the representation of a + 'long double' is safe in practice, despite of the "aliasing rules" of + C99, because the GCC docs say + "Even with '-fstrict-aliasing', type-punning is allowed, provided the + memory is accessed through the union type." + and similarly for other compilers. */ +# define NWORDS \ + ((sizeof (float) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + union { float value; unsigned int word[NWORDS]; } m; + m.value = arg; + return (m.word[FLT_SIGNBIT_WORD] >> FLT_SIGNBIT_BIT) & 1; +#elif HAVE_COPYSIGNF_IN_LIBC + return copysignf (1.0f, arg) < 0; +#else + /* This does not do the right thing for NaN, but this is irrelevant for + most use cases. */ + if (isnanf (arg)) + return 0; + if (arg < 0.0f) + return 1; + else if (arg == 0.0f) + { + /* Distinguish 0.0f and -0.0f. */ + static float plus_zero = 0.0f; + float arg_mem = arg; + return (memcmp (&plus_zero, &arg_mem, SIZEOF_FLT) != 0); + } + else + return 0; +#endif +} diff --git a/glib/gnulib/signbitl.c b/glib/gnulib/signbitl.c new file mode 100644 index 000000000..b1714aadc --- /dev/null +++ b/glib/gnulib/signbitl.c @@ -0,0 +1,64 @@ +/* signbit() macro: Determine the sign bit of a floating-point number. + Copyright (C) 2007, 2009-2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General PublicLicense as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General PublicLicense for more details. + + You should have received a copy of the GNU Lesser General PublicLicense + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include + +#include +#include "isnanl-nolibm.h" +#include "float+.h" + +#ifdef gl_signbitl_OPTIMIZED_MACRO +# undef gl_signbitl +#endif + +int +gl_signbitl (long double arg) +{ +#if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT + /* The use of a union to extract the bits of the representation of a + 'long double' is safe in practice, despite of the "aliasing rules" of + C99, because the GCC docs say + "Even with '-fstrict-aliasing', type-punning is allowed, provided the + memory is accessed through the union type." + and similarly for other compilers. */ +# define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + union { long double value; unsigned int word[NWORDS]; } m; + m.value = arg; + return (m.word[LDBL_SIGNBIT_WORD] >> LDBL_SIGNBIT_BIT) & 1; +#elif HAVE_COPYSIGNL_IN_LIBC + return copysignl (1.0L, arg) < 0; +#else + /* This does not do the right thing for NaN, but this is irrelevant for + most use cases. */ + if (isnanl (arg)) + return 0; + if (arg < 0.0L) + return 1; + else if (arg == 0.0L) + { + /* Distinguish 0.0L and -0.0L. */ + static long double plus_zero = 0.0L; + long double arg_mem = arg; + return (memcmp (&plus_zero, &arg_mem, SIZEOF_LDBL) != 0); + } + else + return 0; +#endif +} From 35de28769030b9d1fe0067f534ed12803a19c29b Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Thu, 28 Mar 2019 18:34:02 +0800 Subject: [PATCH 3/4] Update glib/gnulib/README List the added gnulib modules that need to be updated. --- glib/gnulib/README | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/glib/gnulib/README b/glib/gnulib/README index 78a264c57..2fd920e9b 100644 --- a/glib/gnulib/README +++ b/glib/gnulib/README @@ -44,7 +44,8 @@ To update: * Run gnulib-tool --lgpl=2 --import --lib=libgnu --source-base=lib \ --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. \ --no-conditional-dependencies --no-libtool --macro-prefix=gl \ - isnand-nolibm isnanl-nolibm printf-frexpl vasnprintf + isnand-nolibm isnanf-nolibm isnanl-nolibm printf-frexpl \ + signbit vasnprintf * Then pick out the files that are already in glib/gnulib subdirectory (the rest of the files are not needed): @@ -56,6 +57,8 @@ gnulib_math.h.in (rename from math.in.h) isnan.c isnand.c isnand-nolibm.h +isnanf.c +isnanf-nolibm.h isnanl.c isnanl-nolibm.h printf-args.c @@ -66,6 +69,9 @@ printf-frexpl.c printf-frexpl.h printf-parse.c printf-parse.h +signbitd.c +signbitf.c +signbitl.c vasnprintf.c vasnprintf.h verify.h From de5761db487d4d01c9fdc28e7e1542656d140285 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Fri, 29 Mar 2019 01:07:20 +0800 Subject: [PATCH 4/4] glib/gnulib: Include gnulib_math.h in place of math.h For the new gnulib modules that were added, include gnulib_math.h in place of math.h, so that the replacement functions can be properly referenced. --- glib/gnulib/signbitd.c | 2 +- glib/gnulib/signbitf.c | 2 +- glib/gnulib/signbitl.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/glib/gnulib/signbitd.c b/glib/gnulib/signbitd.c index 7b20f9b2c..dfc1c9092 100644 --- a/glib/gnulib/signbitd.c +++ b/glib/gnulib/signbitd.c @@ -17,7 +17,7 @@ #include /* Specification. */ -#include +#include #include #include "isnand-nolibm.h" diff --git a/glib/gnulib/signbitf.c b/glib/gnulib/signbitf.c index 57e6ef4c7..573d6d975 100644 --- a/glib/gnulib/signbitf.c +++ b/glib/gnulib/signbitf.c @@ -17,7 +17,7 @@ #include /* Specification. */ -#include +#include #include #include "isnanf-nolibm.h" diff --git a/glib/gnulib/signbitl.c b/glib/gnulib/signbitl.c index b1714aadc..11b3e66c9 100644 --- a/glib/gnulib/signbitl.c +++ b/glib/gnulib/signbitl.c @@ -17,7 +17,7 @@ #include /* Specification. */ -#include +#include #include #include "isnanl-nolibm.h"