This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Don't constant fold 1.0/0.0 at compile-time
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Richard Henderson <rth at redhat dot com>
- Date: Tue, 1 Jul 2003 02:12:22 -0600 (MDT)
- Subject: [PATCH] Don't constant fold 1.0/0.0 at compile-time
Well, it looks like I was suckered into this one. Little did I realise...
The following patch attempts to avoid constant folding floating point
division by zero at compile-time. The IEEE standard states that division
by zero may raise an exception and its evaluation is therefore observable
at run-time. Hence if we evaluate 1.0/0.0 to +Inf, 0.0/0.0 to NaN and
-1.0/0.0 to -Inf at compile-time, we'd loose this exception. This was
noticed by RTH in the glibc testsuite where we'd turn pow(0,-1) into the
equivalent 1.0/0.0, which was then folded, loosing the expected trap.
Simple, says I, we simply avoid constant folding this expression in
fold based upon flag_trapping_math. The first problem is that this
expression is not only evaluated by "fold", but also at the RTL-level
by simplify_binary_operation in simplify-rtx.c. Hence, we need to
place identical code there.
But the real issue is that we've now (ever so slightly) changed the
language. 0.0/0.0 is now no longer recognized as a constant expression,
hence code such as the initialized global variable in fp-cmp-1.c now
fail to compile:
double dnan = 1.0/0.0 - 1.0/0.0;
Doh!. Tricky, says I, but we can work around this particular problem
by using lang_hooks.decl.global_bindings. This language hook is used
by "fold" to determine whether the current expression is at global
scope, and to therefore avoid using SAVE_EXPR. Otherwise, in our
example above we might wrap 1.0/0.0 in a SAVE/EXPR and then try and
subtract the saved value from itself. Doh! Not good without RTL...
So I wrapped the checks inside a (*lang_hooks.decl.global_bindings)()
test, which resolved most testsuite regressions, but left three. These
were fp-cmp-4.c, fp-cmp-5.c and fp-cmp-8.c in gcc.c-tortute/execute/ieee.
All of three use code that looks like:
void foo()
{
static double bar = 1.0/0.0;
...
}
Notice that "bar" is no longer at global scope and that therefore the
division is no longer a constant expression. Arghhhh!
I've absolutely no idea what the language standards have to say about
this but it's beginning to look ugly. Is there some mechanism that fold
can use to determine whether we're folding an initializer? Not only for
division by zero, but also for SAVE_EXPRs and other "code generation"
constant folding transformations (this might help tree-ssa for example).
Could one of the language lawyers post their opinions on "x = 1.0/0.0"?
I think C++ can survive this and initialize the static variable at
run-time, and likewise the Java folks are probably happy not to loose
the java.lang.ArithmeticException. But I'm most worried about C.
What do other compilers do?
The patch below is the best I've come up with so far. We no longer
accept division by zero as a constant expression, except to initialize
global variables. Hence, the static example above is no longer valid.
To avoid this problem, the three examples of this idiom in the testsuite
are changed to use either __builtin_nan("") or __builtin_inf() which
are considered constant and are therefore evaluated at compile time.
Hopefully, this solution is acceptable, or at least better than the
current state of affairs.
The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all languages except treelang, and regression tested
with a top-level "make -k check" with no new failures. Richard, could
you confirm that this resolves your glibc testsuite regressions?
Ok for mainline?
2003-07-01 Roger Sayle <roger@eyesopen.com>
* fold-const.c (const_binop): Avoid performing the FP operation at
compile-time, if either operand is NaN and we honor signaling NaNs,
or if we're dividing by zero and either flag_trapping_math is set
or the desired mode doesn't support infinities.
* simplify-rtx.c (simplify_binary_operation): Likewise.
* gcc.c-torture/execute/ieee/fp-cmp-4.c: Avoid 0.0/0.0.
* gcc.c-torture/execute/ieee/fp-cmp-5.c: Avoid 0.0/0.0.
* gcc.c-torture/execute/ieee/fp-cmp-8.c: Avoid 0.0/0.0 and 1.0/0.0.
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.269
diff -c -3 -p -r1.269 fold-const.c
*** fold-const.c 29 Jun 2003 13:53:07 -0000 1.269
--- fold-const.c 1 Jul 2003 02:34:50 -0000
*************** const_binop (code, arg1, arg2, notrunc)
*** 1280,1293 ****
if (TREE_CODE (arg1) == REAL_CST)
{
REAL_VALUE_TYPE d1;
REAL_VALUE_TYPE d2;
REAL_VALUE_TYPE value;
! tree t;
d1 = TREE_REAL_CST (arg1);
d2 = TREE_REAL_CST (arg2);
/* If either operand is a NaN, just return it. Otherwise, set up
for floating-point trap; we return an overflow. */
if (REAL_VALUE_ISNAN (d1))
--- 1280,1314 ----
if (TREE_CODE (arg1) == REAL_CST)
{
+ enum machine_mode mode;
REAL_VALUE_TYPE d1;
REAL_VALUE_TYPE d2;
REAL_VALUE_TYPE value;
! tree t, type;
d1 = TREE_REAL_CST (arg1);
d2 = TREE_REAL_CST (arg2);
+ type = TREE_TYPE (arg1);
+ mode = TYPE_MODE (type);
+
+ /* Don't worry about exceptions when initializing globals. */
+ if ((*lang_hooks.decls.global_bindings_p) () == 0)
+ {
+ /* Don't perform operation if we honor signaling NaNs and
+ either operand is a NaN. */
+ if (HONOR_SNANS (mode)
+ && (REAL_VALUE_ISNAN (d1) || REAL_VALUE_ISNAN (d2)))
+ return NULL_TREE;
+
+ /* Don't perform operation if it would raise a division
+ by zero exception. */
+ if (code == RDIV_EXPR
+ && REAL_VALUES_EQUAL (d2, dconst0)
+ && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
+ return NULL_TREE;
+ }
+
/* If either operand is a NaN, just return it. Otherwise, set up
for floating-point trap; we return an overflow. */
if (REAL_VALUE_ISNAN (d1))
*************** const_binop (code, arg1, arg2, notrunc)
*** 1297,1305 ****
REAL_ARITHMETIC (value, code, d1, d2);
! t = build_real (TREE_TYPE (arg1),
! real_value_truncate (TYPE_MODE (TREE_TYPE (arg1)),
! value));
TREE_OVERFLOW (t)
= (force_fit_type (t, 0)
--- 1318,1324 ----
REAL_ARITHMETIC (value, code, d1, d2);
! t = build_real (type, real_value_truncate (mode, value));
TREE_OVERFLOW (t)
= (force_fit_type (t, 0)
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.144
diff -c -3 -p -r1.144 simplify-rtx.c
*** simplify-rtx.c 17 Jun 2003 00:02:06 -0000 1.144
--- simplify-rtx.c 1 Jul 2003 02:34:51 -0000
*************** simplify_binary_operation (code, mode, o
*** 943,951 ****
f0 = real_value_truncate (mode, f0);
f1 = real_value_truncate (mode, f1);
if (code == DIV
! && !MODE_HAS_INFINITIES (mode)
! && REAL_VALUES_EQUAL (f1, dconst0))
return 0;
REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
--- 943,955 ----
f0 = real_value_truncate (mode, f0);
f1 = real_value_truncate (mode, f1);
+ if (HONOR_SNANS (mode)
+ && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
+ return 0;
+
if (code == DIV
! && REAL_VALUES_EQUAL (f1, dconst0)
! && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
return 0;
REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
Index: fp-cmp-4.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-4.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 fp-cmp-4.c
*** fp-cmp-4.c 28 Aug 2001 00:59:33 -0000 1.2
--- fp-cmp-4.c 1 Jul 2003 07:43:24 -0000
*************** test_islessgreater(double x, double y, i
*** 88,94 ****
}
}
! #define NAN (0.0 / 0.0)
int
main()
--- 88,94 ----
}
}
! #define NAN __builtin_nan ("")
int
main()
Index: fp-cmp-5.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-5.c,v
retrieving revision 1.1
diff -c -3 -p -r1.1 fp-cmp-5.c
*** fp-cmp-5.c 28 Aug 2001 00:59:33 -0000 1.1
--- fp-cmp-5.c 1 Jul 2003 07:43:24 -0000
*************** one_test(double x, double y, int expecte
*** 82,88 ****
abort ();
}
! #define NAN (0.0 / 0.0)
int
main()
--- 82,88 ----
abort ();
}
! #define NAN __builtin_nan("")
int
main()
Index: fp-cmp-8.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-8.c,v
retrieving revision 1.1
diff -c -3 -p -r1.1 fp-cmp-8.c
*** fp-cmp-8.c 5 May 2003 19:33:52 -0000 1.1
--- fp-cmp-8.c 1 Jul 2003 07:43:24 -0000
*************** one_test(double x, double y, int expecte
*** 83,90 ****
abort ();
}
! #define NAN (0.0 / 0.0)
! #define INF (1.0 / 0.0)
int
main()
--- 83,90 ----
abort ();
}
! #define NAN __builtin_nan("")
! #define INF __builtin_inf()
int
main()
Roger
--
Roger Sayle, E-mail: roger@eyesopen.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833