[PATCH] c++: Disable -frounding-math during manifestly constant evaluation [PR96862]

Jason Merrill jason@redhat.com
Wed Sep 2 20:55:14 GMT 2020


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.

>> The following patch has been bootstrapped/regtested on x86_64-linux and
>> i686-linux, but see above, maybe we want something else.
>>
>> 2020-09-01  Jakub Jelinek  <jakub@redhat.com>
>>
>>     PR c++/96862
>>     * constexpr.c (cxx_eval_outermost_constant_expr): Temporarily disable
>>     flag_rounding_math during manifestly constant evaluation.

OK.

>>     * g++.dg/cpp1z/constexpr-96862.C: New test.
>>
>> --- gcc/cp/constexpr.c.jj    2020-08-31 14:10:15.826921458 +0200
>> +++ gcc/cp/constexpr.c    2020-08-31 15:41:26.429964532 +0200
>> @@ -6680,6 +6680,8 @@ cxx_eval_outermost_constant_expr (tree t
>>             allow_non_constant, strict,
>>             manifestly_const_eval || !allow_non_constant };
>>
>> +  /* Turn off -frounding-math for manifestly constant evaluation.  */
>> +  warning_sentinel rm (flag_rounding_math, ctx.manifestly_const_eval);
>>   tree type = initialized_type (t);
>>   tree r = t;
>>   bool is_consteval = false;
>> --- gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C.jj    2020-08-31 
>> 15:50:07.847473028 +0200
>> +++ gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C    2020-08-31 
>> 15:49:40.829861168 +0200
>> @@ -0,0 +1,20 @@
>> +// PR c++/96862
>> +// { dg-do compile { target c++17 } }
>> +// { dg-additional-options "-frounding-math" }
>> +
>> +constexpr double a = 0x1.0p+100 + 0x1.0p-100;
>> +const double b = 0x1.0p+100 + 0x1.0p-100;
>> +const double &&c = 0x1.0p+100 + 0x1.0p-100;
>> +static_assert (0x1.0p+100 + 0x1.0p-100 == 0x1.0p+100, "");
>> +
>> +void
>> +foo ()
>> +{
>> +  constexpr double d = 0x1.0p+100 + 0x1.0p-100;
>> +  const double e = 0x1.0p+100 + 0x1.0p-100;
>> +  const double &&f = 0x1.0p+100 + 0x1.0p-100;
>> +  static_assert (0x1.0p+100 + 0x1.0p-100 == 0x1.0p+100, "");
>> +}
>> +
>> +const double &g = a;
>> +const double &h = b;
>>
>>     Jakub
> 



More information about the Gcc-patches mailing list