From a5dd6b69fcbe74c02d4821ac2daf2b8c9f819f6e Mon Sep 17 00:00:00 2001 From: Marius Hillenbrand Date: Tue, 1 Dec 2020 11:02:27 +0100 Subject: [PATCH] IBM Z: Configure excess precision for float at compile-time Historically, float_t has been defined as double on s390 and gcc would emit double precision insns for evaluating float expressions when in standard-compliant mode. Configure that behavior at compile-time as prep for changes in glibc: When glibc ties float_t to double, keep the old behavior; when glibc derives float_t from FLT_EVAL_METHOD (as on most other archs), revert to the default behavior (i.e., FLT_EVAL_METHOD_PROMOTE_TO_FLOAT). Provide a configure option --enable-s390-excess-float-precision to override the check. gcc/ChangeLog: 2020-12-01 Marius Hillenbrand * configure.ac: Add configure option --enable-s390-excess-float-precision and check to derive default from glibc. * config/s390/s390.c: Guard s390_excess_precision with an ifdef for ENABLE_S390_EXCESS_FLOAT_PRECISION. * doc/install.texi: Document --enable-s390-excess-float-precision. * configure: Regenerate. * config.in: Regenerate. --- gcc/config.in | 4 +++ gcc/config/s390/s390.c | 27 +++++++++++---- gcc/configure | 77 ++++++++++++++++++++++++++++++++++++++++-- gcc/configure.ac | 45 ++++++++++++++++++++++++ gcc/doc/install.texi | 10 ++++++ 5 files changed, 154 insertions(+), 9 deletions(-) diff --git a/gcc/config.in b/gcc/config.in index 3221dae411c..cc6276d0df0 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -236,6 +236,10 @@ /* Define if you want runtime assertions enabled. This is a cheap check. */ #undef ENABLE_RUNTIME_CHECKING +/* Define to enable evaluating float expressions with double precision in + standards-compatible mode on s390 targets. */ +#undef ENABLE_S390_EXCESS_FLOAT_PRECISION + /* Define if you want all operations on trees (the basic data structure of the front ends) to be checked for dynamic type safety at runtime. This is moderately expensive. */ diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 6983e363252..02f18366aa1 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -16376,20 +16376,28 @@ s390_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1, const_tree ty return NULL; } -/* Implement TARGET_C_EXCESS_PRECISION. +#if ENABLE_S390_EXCESS_FLOAT_PRECISION == 1 +/* Implement TARGET_C_EXCESS_PRECISION to maintain historic behavior with older + glibc versions - FIXME: For historical reasons, float_t and double_t are typedef'ed to + For historical reasons, float_t and double_t had been typedef'ed to double on s390, causing operations on float_t to operate in a higher precision than is necessary. However, it is not the case that SFmode operations have implicit excess precision, and we generate more optimal code if we let the compiler know no implicit extra precision is added. - That means when we are compiling with -fexcess-precision=fast, the value - we set for FLT_EVAL_METHOD will be out of line with the actual precision of - float_t (though they would be correct for -fexcess-precision=standard). + With a glibc with that "historic" definition, configure will enable this hook + to set FLT_EVAL_METHOD to 1 for -fexcess-precision=standard (e.g., as implied + by -std=cXY). That means when we are compiling with -fexcess-precision=fast, + the value we set for FLT_EVAL_METHOD will be out of line with the actual + precision of float_t. - A complete fix would modify glibc to remove the unnecessary typedef - of float_t to double. */ + Newer versions of glibc will be modified to derive the definition of float_t + from FLT_EVAL_METHOD on s390x, as on many other architectures. There, + configure will disable this hook by default, so that we defer to the default + of FLT_EVAL_METHOD_PROMOTE_TO_FLOAT and a resulting typedef of float_t to + float. Note that in that scenario, float_t and FLT_EVAL_METHOD will be in + line independent of -fexcess-precision. */ static enum flt_eval_method s390_excess_precision (enum excess_precision_type type) @@ -16412,6 +16420,7 @@ s390_excess_precision (enum excess_precision_type type) } return FLT_EVAL_METHOD_UNPREDICTABLE; } +#endif /* Implement the TARGET_ASAN_SHADOW_OFFSET hook. */ @@ -16708,8 +16717,12 @@ s390_shift_truncation_mask (machine_mode mode) #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true +#if ENABLE_S390_EXCESS_FLOAT_PRECISION == 1 +/* This hook is only needed to maintain the historic behavior with glibc + versions that typedef float_t to double. */ #undef TARGET_C_EXCESS_PRECISION #define TARGET_C_EXCESS_PRECISION s390_excess_precision +#endif #undef TARGET_SCHED_ADJUST_PRIORITY #define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority diff --git a/gcc/configure b/gcc/configure index 3316dd72452..de5fb508182 100755 --- a/gcc/configure +++ b/gcc/configure @@ -1024,6 +1024,7 @@ with_diagnostics_color with_diagnostics_urls enable_default_pie enable_cet +enable_s390_excess_float_precision ' ac_precious_vars='build_alias host_alias @@ -1783,6 +1784,9 @@ Optional Features: disable libquadmath support for Fortran --enable-default-pie enable Position Independent Executable as default --enable-cet enable Intel CET in host libraries [default=auto] + --enable-s390-excess-float-precision + on s390 targets, evaluate float with double + precision when in standards-conforming mode Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -19180,7 +19184,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 19183 "configure" +#line 19187 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -19286,7 +19290,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 19289 "configure" +#line 19293 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -31731,6 +31735,75 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_pushpopstate_support" >&5 $as_echo "$ld_pushpopstate_support" >&6; } +# On s390, float_t has historically been statically defined as double for no +# good reason. To comply with the C standard in the light of this definition, +# gcc has evaluated float expressions in double precision when in +# standards-compatible mode or when given -fexcess-precision=standard. To enable +# a smooth transition towards the new model used by most architectures, where +# gcc describes its behavior via the macro __FLT_EVAL_METHOD__ and glibc derives +# float_t from that, this behavior can be configured with +# --enable-s390-excess-float-precision. When given as enabled, that flag selects +# the old model. When omitted, native builds will derive the flag from the +# behavior of glibc. When glibc clamps float_t to double, gcc follows the old +# model. In any other case, it defaults to the new model. +# Check whether --enable-s390-excess-float-precision was given. +if test "${enable_s390_excess_float_precision+set}" = set; then : + enableval=$enable_s390_excess_float_precision; +else + enable_s390_excess_float_precision=auto +fi + + +case $target in + s390*-linux*) + if test "$target" = "$host" -a "$host" = "$build" -a \ + x"$enable_s390_excess_float_precision" = xauto; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc clamping float_t to double" >&5 +$as_echo_n "checking for glibc clamping float_t to double... " >&6; } +if ${gcc_cv_float_t_clamped_to_double+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define __FLT_EVAL_METHOD__ 0 +#include +int main() { + return !(sizeof(float_t) == sizeof(double)); +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + gcc_cv_float_t_clamped_to_double=yes +else + gcc_cv_float_t_clamped_to_double=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_float_t_clamped_to_double" >&5 +$as_echo "$gcc_cv_float_t_clamped_to_double" >&6; } + if test x"$gcc_cv_float_t_clamped_to_double" = xyes; then + enable_s390_excess_float_precision=yes + fi + fi + + + if test x"$enable_s390_excess_float_precision" = xyes; then + +$as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h + + fi + ;; +esac + # Configure the subdirectories # AC_CONFIG_SUBDIRS($subdirs) diff --git a/gcc/configure.ac b/gcc/configure.ac index b410428b4fc..24679a540c1 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -7318,6 +7318,51 @@ if test x"$ld_pushpopstate_support" = xyes; then fi AC_MSG_RESULT($ld_pushpopstate_support) +# On s390, float_t has historically been statically defined as double for no +# good reason. To comply with the C standard in the light of this definition, +# gcc has evaluated float expressions in double precision when in +# standards-compatible mode or when given -fexcess-precision=standard. To enable +# a smooth transition towards the new model used by most architectures, where +# gcc describes its behavior via the macro __FLT_EVAL_METHOD__ and glibc derives +# float_t from that, this behavior can be configured with +# --enable-s390-excess-float-precision. When given as enabled, that flag selects +# the old model. When omitted, native builds will derive the flag from the +# behavior of glibc. When glibc clamps float_t to double, gcc follows the old +# model. In any other case, it defaults to the new model. +AC_ARG_ENABLE(s390-excess-float-precision, + [AS_HELP_STRING([--enable-s390-excess-float-precision], + [on s390 targets, evaluate float with double precision + when in standards-conforming mode])], + [],[enable_s390_excess_float_precision=auto]) + +case $target in + s390*-linux*) + if test "$target" = "$host" -a "$host" = "$build" -a \ + x"$enable_s390_excess_float_precision" = xauto; then + AC_CACHE_CHECK([for glibc clamping float_t to double], + gcc_cv_float_t_clamped_to_double, + [AC_RUN_IFELSE([AC_LANG_SOURCE([ +#define __FLT_EVAL_METHOD__ 0 +#include +int main() { + return !(sizeof(float_t) == sizeof(double)); +}])], + [gcc_cv_float_t_clamped_to_double=yes], + [gcc_cv_float_t_clamped_to_double=no])]) + if test x"$gcc_cv_float_t_clamped_to_double" = xyes; then + enable_s390_excess_float_precision=yes + fi + fi + + GCC_TARGET_TEMPLATE(ENABLE_S390_EXCESS_FLOAT_PRECISION) + if test x"$enable_s390_excess_float_precision" = xyes; then + AC_DEFINE(ENABLE_S390_EXCESS_FLOAT_PRECISION, 1, +[Define to enable evaluating float expressions with double precision in +standards-compatible mode on s390 targets.]) + fi + ;; +esac + # Configure the subdirectories # AC_CONFIG_SUBDIRS($subdirs) diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 021c347cc09..a38ca3e3ce8 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -2270,6 +2270,16 @@ information in object. The option is disabled by default. It is enabled on RISC-V/ELF (bare-metal) target if target binutils supported. + +@item --enable-s390-excess-float-precision +@itemx --disable-s390-excess-float-precision +On s390(x) targets, enable treatment of float expressions with double precision +when in standards-compliant mode (e.g., when @code{--std=c99} or +@code{-fexcess-precision=standard} are given). + +For a native build, the option's default is derived from glibc's behavior. When +glibc clamps float_t to double, gcc follows and enables the option. In all other +cases, it defaults to off. @end table @subheading Cross-Compiler-Specific Options -- 2.30.2