Go to file
Roger Sayle 1be4878116 Fix middle-end/85811: Introduce tree_expr_maybe_non_p et al.
The motivation for this patch is PR middle-end/85811, a wrong-code
regression entitled "Invalid optimization with fmax, fabs and nan".
The optimization involves assuming max(x,y) is non-negative if (say)
y is non-negative, i.e. max(x,2.0).  Unfortunately, this is an invalid
assumption in the presence of NaNs.  Hence max(x,+qNaN), with IEEE fmax
semantics will always return x even though the qNaN is non-negative.
Worse, max(x,2.0) may return a negative value if x is -sNaN.

I'll quote Joseph Myers (many thanks) who describes things clearly as:
> (a) When both arguments are NaNs, the return value should be a qNaN,
> but sometimes it is an sNaN if at least one argument is an sNaN.
> (b) Under TS 18661-1 semantics, if either argument is an sNaN then the
> result should be a qNaN (whereas if one argument is a qNaN and the
> other is not a NaN, the result should be the non-NaN argument).
> Various implementations treat sNaNs like qNaNs here.

Under this logic, the tree_expr_nonnegative_p for IEEE fmax should be:

    CASE_CFN_FMAX:
    CASE_CFN_FMAX_FN:
      /* Usually RECURSE (arg0) || RECURSE (arg1) but NaNs complicate
         things.  In the presence of sNaNs, we're only guaranteed to be
         non-negative if both operands are non-negative.  In the presence
         of qNaNs, we're non-negative if either operand is non-negative
         and can't be a qNaN, or if both operands are non-negative.  */
      if (tree_expr_maybe_signaling_nan_p (arg0) ||
          tree_expr_maybe_signaling_nan_p (arg1))
        return RECURSE (arg0) && RECURSE (arg1);
      return RECURSE (arg0) ? (!tree_expr_maybe_nan_p (arg0)
                              || RECURSE (arg1))
                            : (RECURSE (arg1)
                              && !tree_expr_maybe_nan_p (arg1));

Which indeed resolves the wrong code in the PR.  The infrastructure that
makes this possible are the two new functions tree_expr_maybe_nan_p and
tree_expr_maybe_signaling_nan_p which test whether a value may potentially
be a NaN or a signaling NaN respectively.  In fact, this patch adds seven
new predicates to the middle-end:

bool tree_expr_finite_p (const_tree);
bool tree_expr_infinite_p (const_tree);
bool tree_expr_maybe_infinite_p (const_tree);
bool tree_expr_signaling_nan_p (const_tree);
bool tree_expr_maybe_signaling_nan_p (const_tree);
bool tree_expr_nan_p (const_tree);
bool tree_expr_maybe_nan_p (const_tree);

These functions correspond to the "must" and "may" operators in modal logic,
and allow us to triage expressions in the middle-end; definitely a NaN,
definitely not a NaN, and unknown at compile-time, etc.  A prime example of
the utility of these functions is that a IEEE floating point value promoted
from an integer type can't be a NaN or infinite.  Hence (double)i+0.0 where
i is an integer can be simplified to (double)i even with -fsignaling-nans.
Currently in GCC optimizations are enabled/disabled based on whether the
expression's type supports NaNs or sNaNs; with these new predicates they
can be controlled by whether the actual operands may or may not be NaNs.

Having added these extremely useful helper functions to the middle-end,
I couldn't help by use then in a few places in fold-const.c, builtins.c
and match.pd.  In the near term, these can/should be used in places
where the tree optimizers test for HONOR_NANS, HONOR_INFINITIES or
HONOR_SNANS, or explicitly test whether a REAL_CST is a NaN or Inf.
In the longer term (I'm not volunteering) these predicates could perhaps
be hooked into the middle-end's SSA chaining and/or VRP machinery,
allowing finiteness to propagated around the CFG, much like we
currently propagate value ranges.

This patch has been tested on x86_64-pc-linux-gnu with a "make bootstrap"
and "make -k check".
Ok for mainline?

2020-08-15  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
	PR middle-end/85811
	* fold-const.c (tree_expr_finite_p): New function to test whether
	a tree expression must be finite, i.e. not a FP NaN or infinity.
	(tree_expr_infinite_p):  New function to test whether a tree
	expression must be infinite, i.e. a FP infinity.
	(tree_expr_maybe_infinite_p): New function to test whether a tree
	expression may be infinite, i.e. a FP infinity.
	(tree_expr_signaling_nan_p): New function to test whether a tree
	expression must evaluate to a signaling NaN (sNaN).
	(tree_expr_maybe_signaling_nan_p): New function to test whether a
	tree expression may be a signaling NaN (sNaN).
	(tree_expr_nan_p): New function to test whether a tree expression
	must evaluate to a (quiet or signaling) NaN.
	(tree_expr_maybe_nan_p): New function to test whether a tree
	expression me be a (quiet or signaling) NaN.

	(tree_binary_nonnegative_warnv_p) [MAX_EXPR]: In the presence
	of NaNs, MAX_EXPR is only guaranteed to be non-negative, if both
	operands are non-negative.
	(tree_call_nonnegative_warnv_p) [CASE_CFN_FMAX,CASE_CFN_FMAX_FN]:
	In the presence of signaling NaNs, fmax is only guaranteed to be
	non-negative if both operands are negative.  In the presence of
	quiet NaNs, fmax is non-negative if either operand is non-negative
	and not a qNaN, or both operands are non-negative.

	* fold-const.h (tree_expr_finite_p, tree_expr_infinite_p,
	tree_expr_maybe_infinite_p, tree_expr_signaling_nan_p,
	tree_expr_maybe_signaling_nan_p, tree_expr_nan_p,
	tree_expr_maybe_nan_p): Prototype new functions here.

	* builtins.c (fold_builtin_classify) [BUILT_IN_ISINF]: Fold to
	a constant if argument is known to be (or not to be) an Infinity.
	[BUILT_IN_ISFINITE]: Fold to a constant if argument is known to
	be (or not to be) finite.
	[BUILT_IN_ISNAN]: Fold to a constant if argument is known to be
	(or not to be) a NaN.
	(fold_builtin_fpclassify): Check tree_expr_maybe_infinite_p and
	tree_expr_maybe_nan_p instead of HONOR_INFINITIES and HONOR_NANS
	respectively.
	(fold_builtin_unordered_cmp): Fold UNORDERED_EXPR to a constant
	when its arguments are known to be (or not be) NaNs.  Check
	tree_expr_maybe_nan_p instead of HONOR_NANS when choosing between
	unordered and regular forms of comparison operators.

	* match.pd (ordered(x,y)->true/false): Constant fold ORDERED_EXPR
	if its operands are known to be (or not to be) NaNs.
	(unordered(x,y)->true/false): Constant fold UNORDERED_EXPR if its
	operands are known to be (or not to be) NaNs.
	(sqrt(x)*sqrt(x)->x): Check tree_expr_maybe_signaling_nan_p instead
	of HONOR_SNANS.

gcc/testsuite/ChangeLog
	PR middle-end/85811
	* gcc.dg/pr85811.c: New test.
	* gcc.dg/fold-isfinite-1.c: New test.
	* gcc.dg/fold-isfinite-2.c: New test.
	* gcc.dg/fold-isinf-1.c: New test.
	* gcc.dg/fold-isinf-2.c: New test.
	* gcc.dg/fold-isnan-1.c: New test.
	* gcc.dg/fold-isnan-2.c: New test.
2020-11-18 15:09:46 -07:00
INSTALL README: Do not mention CVS. 2014-10-12 15:05:28 +00:00
config Fixup config/ChangeLog. 2020-09-10 10:17:51 +02:00
contrib Daily bump. 2020-11-17 00:16:27 +00:00
fixincludes aix: Fixinclude 2020-11-18 10:33:30 -08:00
gcc Fix middle-end/85811: Introduce tree_expr_maybe_non_p et al. 2020-11-18 15:09:46 -07:00
gnattools PR81878: fix --disable-bootstrap --enable-languages=ada 2018-11-20 00:07:47 +00:00
gotools Daily bump. 2020-10-30 00:16:29 +00:00
include Daily bump. 2020-09-25 00:16:27 +00:00
intl intl: Unbreak intl build with bison 3 when no regeneration is needed [PR92008] 2020-04-16 11:55:00 +02:00
libada Add `--with-toolexeclibdir=' configuration option 2020-01-24 11:24:25 +00:00
libatomic Daily bump. 2020-10-12 00:16:25 +00:00
libbacktrace Daily bump. 2020-10-21 00:16:36 +00:00
libcc1 Daily bump. 2020-11-12 00:16:39 +00:00
libcpp preprocessor: C++ module-directives 2020-11-18 10:24:12 -08:00
libdecnumber Daily bump. 2020-07-31 00:16:26 +00:00
libffi Daily bump. 2020-09-25 00:16:27 +00:00
libgcc MSP430: Add 64-bit hardware multiply support 2020-11-18 11:05:27 +00:00
libgfortran Daily bump. 2020-11-02 20:53:00 +00:00
libgo cmd/go, cmd/cgo: update gofrontend mangling checks 2020-11-17 18:32:07 -08:00
libgomp openmp: Retire nest-var ICV for OpenMP 5.1 2020-11-18 11:24:36 -08:00
libhsail-rt Add `--with-toolexeclibdir=' configuration option 2020-01-24 11:24:25 +00:00
libiberty Daily bump. 2020-11-14 00:16:38 +00:00
libitm Daily bump. 2020-10-02 00:16:27 +00:00
libobjc Daily bump. 2020-10-12 00:16:25 +00:00
liboffloadmic Add missing ChangeLog entries. 2020-05-05 16:10:13 +02:00
libphobos d: Add dragonflybsd support for D compiler and runtime 2020-11-18 10:22:06 +01:00
libquadmath Daily bump. 2020-05-30 00:16:27 +00:00
libsanitizer Daily bump. 2020-11-14 00:16:38 +00:00
libssp Daily bump. 2020-05-30 00:16:27 +00:00
libstdc++-v3 libstdc++: Fix ranges::join_view::_Iterator::operator-> [LWG 3500] 2020-11-18 10:23:57 -05:00
libvtv Daily bump. 2020-05-30 00:16:27 +00:00
lto-plugin Daily bump. 2020-09-11 00:16:28 +00:00
maintainer-scripts Daily bump. 2020-05-30 00:16:27 +00:00
zlib Daily bump. 2020-05-30 00:16:27 +00:00
.dir-locals.el
.gitattributes Add *.md diff=md. 2020-01-15 14:29:53 +01:00
.gitignore Add .cache to git ignore. 2020-11-16 12:52:43 +01:00
ABOUT-NLS
COPYING
COPYING.LIB
COPYING.RUNTIME
COPYING3
COPYING3.LIB
ChangeLog Daily bump. 2020-11-17 00:16:27 +00:00
ChangeLog.jit
ChangeLog.tree-ssa
MAINTAINERS MAINTAINERS: add myself for write after approval 2020-11-13 11:01:12 +08:00
Makefile.def Merge top-level configury changes from gdb 2020-04-09 06:52:55 -06:00
Makefile.in Merge top-level configury changes from gdb 2020-04-09 06:52:55 -06:00
Makefile.tpl Makefile.tpl (HOST_EXPORTS): Add CXX_FOR_BUILD. 2019-08-23 15:37:22 -06:00
README
ar-lib Update GCC to autoconf 2.69, automake 1.15.1 (PR bootstrap/82856). 2018-10-31 17:03:16 +00:00
compile
config-ml.in config-ml.in: Suppress output from multi-do recipes 2020-11-09 14:28:37 +00:00
config.guess Update config.sub and config.guess. 2019-09-09 11:14:32 +02:00
config.rpath
config.sub Update config.sub and config.guess. 2019-09-09 11:14:32 +02:00
configure configure: Fix in-tree building of GMP on BSD [PR97302] 2020-10-06 11:49:34 +02:00
configure.ac configure: Fix in-tree building of GMP on BSD [PR97302] 2020-10-06 11:49:34 +02:00
depcomp
install-sh
libtool-ldflags
libtool.m4 [ARM/FDPIC v6 02/24] [ARM] FDPIC: Handle arm*-*-uclinuxfdpiceabi in configure scripts 2019-09-10 09:37:00 +02:00
ltgcc.m4
ltmain.sh Do not use HAVE_DOS_BASED_FILE_SYSTEM for Cygwin. 2020-04-17 09:22:51 +02:00
ltoptions.m4
ltsugar.m4
ltversion.m4
lt~obsolete.m4
missing
mkdep
mkinstalldirs
move-if-change Update move-if-change from gnulib 2014-11-16 16:12:44 +00:00
multilib.am Update GCC to autoconf 2.69, automake 1.15.1 (PR bootstrap/82856). 2018-10-31 17:03:16 +00:00
symlink-tree
test-driver Update GCC to autoconf 2.69, automake 1.15.1 (PR bootstrap/82856). 2018-10-31 17:03:16 +00:00
ylwrap

README

This directory contains the GNU Compiler Collection (GCC).

The GNU Compiler Collection is free software.  See the files whose
names start with COPYING for copying permission.  The manuals, and
some of the runtime libraries, are under different terms; see the
individual source files for details.

The directory INSTALL contains copies of the installation information
as HTML and plain text.  The source of this information is
gcc/doc/install.texi.  The installation information includes details
of what is included in the GCC sources and what files GCC installs.

See the file gcc/doc/gcc.texi (together with other files that it
includes) for usage and porting information.  An online readable
version of the manual is in the files gcc/doc/gcc.info*.

See http://gcc.gnu.org/bugs/ for how to report bugs usefully.

Copyright years on GCC source files may be listed using range
notation, e.g., 1987-2012, indicating that every year in the range,
inclusive, is a copyrightable year that could otherwise be listed
individually.