aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/rs6000
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2023-04-28 08:59:29 +0200
committerJakub Jelinek <jakub@redhat.com>2023-04-28 08:59:29 +0200
commitbd539c9b801bde3a919a5ad16b741ab4f5eca6e3 (patch)
treeec307e301dbd0c6b4a948c2be315b19bcf55b994 /gcc/config/rs6000
parentd76c343d6a6295a8cc612fc19a99156aa0976180 (diff)
downloadgcc-bd539c9b801bde3a919a5ad16b741ab4f5eca6e3.zip
gcc-bd539c9b801bde3a919a5ad16b741ab4f5eca6e3.tar.gz
gcc-bd539c9b801bde3a919a5ad16b741ab4f5eca6e3.tar.bz2
Add targetm.libm_function_max_error
As has been discussed before, the following patch adds target hook for math library function maximum errors measured in ulps. The default is to return ~0U which is a magic maximum value which means nothing is known about precision of the match function. The first argument is unsigned int because enum combined_fn isn't available everywhere where target hooks are included but is expected to be given the enum combined_fn value, although it should be used solely to find out which kind of match function (say sin vs. cos vs. sqrt vs. exp10) rather than its variant (f suffix, no suffix, l suffix, f128 suffix, ...), for which there is the machine_mode argument. The last argument is a bool, if it is false, the function should return maximum known error in ulps for a given function (taking -frounding-math into account if enabled), with 0.5ulps being represented as 0. If it is true, it is about whether the function can return values outside of an intrinsic finite range for the function and by how many ulps. E.g. sin/cos should return result in [-1.,1], if the function is expected to never return values outside of that finite interval, the hook should return 0. Similarly for sqrt such range is [-0.,+Inf]. The patch implements it for glibc only so far, I hope other maintainers can submit details for Solaris, musl, perhaps BSDs, etc. For glibc I've gathered data from: 1) https://www.gnu.org/software/libc/manual/html_node/Errors-in-Math-Functions.html as latest published glibc data 2) https://www.gnu.org/software/libc/manual/2.22/html_node/Errors-in-Math-Functions.html as a few years old glibc data 3) using attached libc-ulps.sh script from glibc git 4) using attached ulp-tester.c (how to invoke in file comment; tested both x86_64, ppc64, ppc64le 50M pseudo-random values in all 4 rounding modes, plus on x86_64 float/double sin/cos using libmvec - see attached libmvec-wrapper.c as well) 5) using attached boundary-tester.c to test for whether sin/cos/sqrt return values outside of the intrinsic ranges for those functions (again, tested on x86_64, ppc64, ppc64le plus on x86_64 using libmvec as well; libmvec with non-default rounding modes is pretty much random number generator it seems) The data is added to various hooks, the generic and generic glibc versions being in targhooks.c so that the various targets can easily override it. The intent is that the generic glibc version handles most of the stuff and specific target arch overrides handle the outliers or special cases. The patch has special case for x86_64 when __FAST_MATH__ is defined (as one can use in that case either libm or libmvec and we don't know which one will be used; so it uses maximum of what libm provides and libmvec), rs6000 (had to add one because cosf has 3ulps on ppc* rather than 1-2ulps on most other targets; MODE_COMPOSITE_P could be in theory handled in the generic code too, but as we have rs6000-linux specific function, it can be done just there), arc-linux (because DFmode sin has 7ulps there compared to 1ulps on other targets, both in default rounding mode and in others) and or1k-linux (while DFmode sin has 1ulps there for default rounding mode, for other rounding modes it has up to 7ulps). Now, for -frounding-math I'm trying to add a few ulps more because I expect it to be much less tested, except that for boundary_p I try to use the numbers I got from the 5) tester. 2023-04-28 Jakub Jelinek <jakub@redhat.com> * target.def (libm_function_max_error): New target hook. * doc/tm.texi.in (TARGET_LIBM_FUNCTION_MAX_ERROR): Add. * doc/tm.texi: Regenerated. * targhooks.h (default_libm_function_max_error, glibc_linux_libm_function_max_error): Declare. * targhooks.cc: Include case-cfn-macros.h. (default_libm_function_max_error, glibc_linux_libm_function_max_error): New functions. * config/linux.h (TARGET_LIBM_FUNCTION_MAX_ERROR): Redefine. * config/linux-protos.h (linux_libm_function_max_error): Declare. * config/linux.cc: Include target.h and targhooks.h. (linux_libm_function_max_error): New function. * config/arc/arc.cc: Include targhooks.h and case-cfn-macros.h. (arc_libm_function_max_error): New function. (TARGET_LIBM_FUNCTION_MAX_ERROR): Redefine. * config/i386/i386.cc (ix86_libc_has_fast_function): Formatting fix. (ix86_libm_function_max_error): New function. (TARGET_LIBM_FUNCTION_MAX_ERROR): Redefine. * config/rs6000/rs6000-protos.h (rs6000_linux_libm_function_max_error): Declare. * config/rs6000/rs6000-linux.cc: Include target.h, targhooks.h, tree.h and case-cfn-macros.h. (rs6000_linux_libm_function_max_error): New function. * config/rs6000/linux.h (TARGET_LIBM_FUNCTION_MAX_ERROR): Redefine. * config/rs6000/linux64.h (TARGET_LIBM_FUNCTION_MAX_ERROR): Redefine. * config/or1k/or1k.cc: Include targhooks.h and case-cfn-macros.h. (or1k_libm_function_max_error): New function. (TARGET_LIBM_FUNCTION_MAX_ERROR): Redefine.
Diffstat (limited to 'gcc/config/rs6000')
-rw-r--r--gcc/config/rs6000/linux.h3
-rw-r--r--gcc/config/rs6000/linux64.h3
-rw-r--r--gcc/config/rs6000/rs6000-linux.cc40
-rw-r--r--gcc/config/rs6000/rs6000-protos.h2
4 files changed, 48 insertions, 0 deletions
diff --git a/gcc/config/rs6000/linux.h b/gcc/config/rs6000/linux.h
index 5d21bef..8dc2a89 100644
--- a/gcc/config/rs6000/linux.h
+++ b/gcc/config/rs6000/linux.h
@@ -50,6 +50,9 @@
#undef TARGET_LIBC_HAS_FUNCTION
#define TARGET_LIBC_HAS_FUNCTION linux_libc_has_function
+#undef TARGET_LIBM_FUNCTION_MAX_ERROR
+#define TARGET_LIBM_FUNCTION_MAX_ERROR rs6000_linux_libm_function_max_error
+
#undef TARGET_OS_CPP_BUILTINS
#define TARGET_OS_CPP_BUILTINS() \
do \
diff --git a/gcc/config/rs6000/linux64.h b/gcc/config/rs6000/linux64.h
index 9e45703..6e4acaf 100644
--- a/gcc/config/rs6000/linux64.h
+++ b/gcc/config/rs6000/linux64.h
@@ -288,6 +288,9 @@ extern int dot_symbols;
#undef TARGET_LIBC_HAS_FUNCTION
#define TARGET_LIBC_HAS_FUNCTION linux_libc_has_function
+#undef TARGET_LIBM_FUNCTION_MAX_ERROR
+#define TARGET_LIBM_FUNCTION_MAX_ERROR rs6000_linux_libm_function_max_error
+
#undef TARGET_OS_CPP_BUILTINS
#define TARGET_OS_CPP_BUILTINS() \
do \
diff --git a/gcc/config/rs6000/rs6000-linux.cc b/gcc/config/rs6000/rs6000-linux.cc
index 35dc109..0f89cb4 100644
--- a/gcc/config/rs6000/rs6000-linux.cc
+++ b/gcc/config/rs6000/rs6000-linux.cc
@@ -23,6 +23,10 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "target.h"
+#include "targhooks.h"
+#include "tree.h"
+#include "case-cfn-macros.h"
/* Implement TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P. */
@@ -36,3 +40,39 @@ rs6000_linux_float_exceptions_rounding_supported_p (void)
else
return TARGET_HARD_FLOAT;
}
+
+/* Implement TARGET_LIBM_FUNCTION_MAX_ERROR. */
+
+unsigned
+rs6000_linux_libm_function_max_error (unsigned cfn, machine_mode mode,
+ bool boundary_p)
+{
+ if (OPTION_GLIBC)
+ {
+ int rnd = flag_rounding_math ? 4 : 0;
+ switch (cfn)
+ {
+ CASE_CFN_SQRT:
+ CASE_CFN_SQRT_FN:
+ if (!boundary_p && MODE_COMPOSITE_P (mode))
+ return 1 + rnd;
+ break;
+ CASE_CFN_COS:
+ CASE_CFN_COS_FN:
+ if (!boundary_p && mode == SFmode)
+ return 3 + rnd;
+ if (!boundary_p && MODE_COMPOSITE_P (mode))
+ return 4 + rnd;
+ break;
+ CASE_CFN_SIN:
+ CASE_CFN_SIN_FN:
+ if (!boundary_p && MODE_COMPOSITE_P (mode))
+ return 1 + rnd;
+ break;
+ default:
+ break;
+ }
+ return glibc_linux_libm_function_max_error (cfn, mode, boundary_p);
+ }
+ return default_libm_function_max_error (cfn, mode, boundary_p);
+}
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 1a4fc1d..9a4cc18 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -334,6 +334,8 @@ extern unsigned char rs6000_class_max_nregs[][LIM_REG_CLASSES];
extern unsigned char rs6000_hard_regno_nregs[][FIRST_PSEUDO_REGISTER];
extern bool rs6000_linux_float_exceptions_rounding_supported_p (void);
+extern unsigned rs6000_linux_libm_function_max_error (unsigned, machine_mode,
+ bool);
/* Pass management. */
namespace gcc { class context; }