- fariborz (fjahanian@apple.com)
Abstract: In the following code the repeated multiplication is folded
into a single
operation (multiplication by Infinity), when compiled for
apple-ppc-darwin target.
For different values of "x" this leads to undeserved or absent
floating point
exceptions, and breaks some of the elementary math functions in Libm.
Occurs
at optimization O1 and higher.
/* test */
static const double C = 0x1.0p1023;
double foo(double x)
{
return ( ( (x * C) * C ) * C );
}
Section 5.1.2.3 Program execution of the Programming languages C
standard says:
13 EXAMPLE 5 Rearrangement for floating-point expressions is often
restricted because of limitations
in precision as well as range. The implementation cannot generally
apply the mathematical associative
rules for addition or multiplication, nor the distributive rule,
because of roundoff error, even
in the absence of overflowand underflow. Likewise, implementations
cannot generally replace decimal
constants in order to rearrange expressions. In the following
fragment, rearrangements suggested by
mathematical rules for real numbers are often not valid (see F.8).
double x, y, z;
/*... */
x=(x*y)*z;
//not equivalent to
x*=y*z;
So, such optimization cannot take place under general optimization
flags.
Question remains, under which flag should we place this specific
unsafe optiomization?
There has been three suggestions, I will address each, one by one.
1. Do this optimization when flag_trapping_math is 0 (default is 1).
"Zero means that floating-point math operations cannot generate a
(user-visible) trap". This includes overflow, underflow. This
certainly
can be the flag to check for. But such an optimization may cause
finite
results which could be incorrect without causing a trap, for example,
a roundoff error.
2. Do this optimization when flag_finite_math_only is 1 (default is
0).
"Allow optimizations for floating-point arithmetic that assume that
arguments and results are not NaNs or +-Infs". Again, result of such
an optimization can be finite but wrong.
3. -funsafe-math-optimizations
"Allow optimizations for floating-point arithmetic that (a) assume
that arguments and results are valid and (b) may violate IEEE or
ANSI standards".
Such an optimization is in violation of Section 5.1.2.3 of ANSI
standards
as noted in above.
Above flag has been used for the following case, among others:
from negate_expr_p(tree) in fold-const.c
case PLUS_EXPR:
if (FLOAT_TYPE_P (type) && !flag_unsafe_math_optimizations)
return false;
/* -(A + B) -> (-B) - A. */
...
/* -(A + B) -> (-A) - B. */
...
So, it seems that flag_unsafe_math_optimizations has been used in
other situations to disallow certain optimizations which are in
violation of ANSI
standards. This is the flag that I check for in my patch.