On Wed, 2 Sep 2020, Jason Merrill via Gcc-patches wrote:

On 9/1/20 6:13 AM, Marc Glisse wrote:
On Tue, 1 Sep 2020, Jakub Jelinek via Gcc-patches wrote:

As discussed in the PR, fold-const.c punts on floating point constant
evaluation if the result is inexact and -frounding-math is turned on.
     /* Don't constant fold this floating point operation if the
        result may dependent upon the run-time rounding mode and
        flag_rounding_math is set, or if GCC's software emulation
        is unable to accurately represent the result.  */
     if ((flag_rounding_math
          || (MODE_COMPOSITE_P (mode) && !flag_unsafe_math_optimizations))
         && (inexact || !real_identical (&result, &value)))
       return NULL_TREE;
Jonathan said that we should be evaluating them anyway, e.g. conceptually
as if they are done with the default rounding mode before user had a chance
to change that, and e.g. in C in initializers it is also ignored.
In fact, fold-const.c for C initializers turns off various other options:

/* Perform constant folding and related simplification of initializer
  expression EXPR.  These behave identically to "fold_buildN" but ignore
  potential run-time traps and exceptions that fold must preserve.  */

#define START_FOLD_INIT \
 int saved_signaling_nans = flag_signaling_nans;\
 int saved_trapping_math = flag_trapping_math;\
 int saved_rounding_math = flag_rounding_math;\
 int saved_trapv = flag_trapv;\
 int saved_folding_initializer = folding_initializer;\
 flag_signaling_nans = 0;\
 flag_trapping_math = 0;\
 flag_rounding_math = 0;\
 flag_trapv = 0;\
 folding_initializer = 1;

#define END_FOLD_INIT \
 flag_signaling_nans = saved_signaling_nans;\
 flag_trapping_math = saved_trapping_math;\
 flag_rounding_math = saved_rounding_math;\
 flag_trapv = saved_trapv;\
 folding_initializer = saved_folding_initializer;

So, shall cxx_eval_outermost_constant_expr instead turn off all those
options (then warning_sentinel wouldn't be the right thing to use, but given
the 8 or how many return stmts in cxx_eval_outermost_constant_expr, we'd
need a RAII class for this.  Not sure about the folding_initializer, that
one is affecting complex multiplication and division constant evaluation
somehow.

I don't think we need to turn off flag_signaling_nans or flag_trapv. I think we want to turn off flag_trapping_math so we can fold 1./0 to inf (still in a context where folding is mandatory). Setting folding_initializer seems consistent with that, enabling infinite results in complex folding (it also forces folding of __builtin_constant_p, which may be redundant with force_folding_builtin_constant_p).

C++ says that division by zero has undefined behavior, and that an expression with undefined behavior is not constant, so we shouldn't fold 1./0 to inf anyway. The same is true of other trapping operations. So clearing flag_signaling_nans, flag_trapping_math, and flag_trapv seems wrong for C++. And folding_initializer seems to be used for the same sort of thing.

So we should actually force flag_trapping_math to true during constexpr
evaluation? And folding_initializer to false, and never mind trapv but
maybe disable wrapv?

#include <limits>
constexpr double a = std::numeric_limits<double>::infinity();
constexpr double b = a + a;
constexpr double c = a - a;
constexpr double d = 1. / a;
constexpr double e = 1. / d;

clang rejects c and e. MSVC rejects e. Intel warns on c.

Gcc rejects only e, and accepts the whole thing if I pass
-fno-trapping-math.

Almost any FP operation is possibly trapping, 1./3. sets FE_INEXACT just as 1./0. sets FE_DIVBYZERO. But the standard says

char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during 
translation

So it doesn't seem like it cares about that? Division by zero is the only one that gets weirdly special-cased...

--
Marc Glisse

Reply via email to