Bug 54192 - -fno-trapping-math by default?
Summary: -fno-trapping-math by default?
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-08-07 12:40 UTC by Marc Glisse
Modified: 2021-09-22 06:20 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-09-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marc Glisse 2012-08-07 12:40:24 UTC
Hello,

I am not sure about the "component" (I am actually more interested in the C++ behavior, but I assume C and C++ will remain the same), or about posting this to bugzilla instead of the mailing-list.

I would like to know people's opinion about making -fno-trapping-math the default. One strong argument in favor is that -fno-rounding-math is the default. The 2 options are quite similar. They both affect "special" use of maths, they both inhibit a number of optimizations, and they both have bugs (not trying to offend anyone here, it is already great that the options are as far as they are).

As someone who needs -frounding-math and for whom -fno-trapping-math is safe and helps performance, you can see why I'd like to change it ;-)
Comment 1 Richard Biener 2012-08-07 12:50:16 UTC
The current reasoning is that the C standard allows the implementation to
say that only round-to-nearest is supported but not that the trapping parts
of IEEE are not honored.  The default should always be standard conformant
behavior.
Comment 2 Marc Glisse 2012-08-07 13:13:46 UTC
Don't you need to tell the compiler (with the FENV_ACCESS pragma) that you are going to look at flags, just like you tell it that you are going to use non-default rounding modes?

"In general, if the state of FENV_ACCESS is ‘‘off’’, the translator can assume that default modes are in effect and the flags are not tested."

The compiler would also need to #undef FE_DOWNWARD in fenv.h if it wants to pretend that it only supports round-to-nearest (there is an "if and only if" in the standard).

I think I see what you mean: if there is only one rounding-mode, then the pragma has no effect on rounding so you can pretend that it is on. But then the same applies to trapping, since the standard explicitly allows for FE_ALL_EXCEPT==0.
Comment 3 Richard Biener 2019-06-24 14:03:17 UTC
flag_trapping_math also guards things like

      /* Don't perform operation if it would raise a division
         by zero exception.  */
      if (code == RDIV_EXPR
          && real_equal (&d2, &dconst0)
          && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
        return NULL_TREE;

so I guess it differs from -frounding-math also in a way that it doesn't
guard FENV access of the exception state (I'd say that is not implemented
at all, not even in the -frounding-math way) but it guards whether
the FENV state is set to trap?  So its default should match the
execution environments default?

So IMHO we should simply document that -frounding-math is about
FENV access (including exception bits) and -fno-trapping-math is
about "exceptions" in the C++ sense (aka traps).
Comment 4 joseph@codesourcery.com 2019-08-01 22:54:31 UTC
On Mon, 24 Jun 2019, rguenth at gcc dot gnu.org wrote:

> so I guess it differs from -frounding-math also in a way that it doesn't
> guard FENV access of the exception state (I'd say that is not implemented
> at all, not even in the -frounding-math way) but it guards whether
> the FENV state is set to trap?  So its default should match the
> execution environments default?

flag_trapping_math is about disallowing local transformations that would 
add or remove the raising of exception flags.  It's nothing to do with 
traps, except insofar as some systems may permit exceptions to result in a 
trap rather than just the raising of a flag.  In particular, F.9#3 should 
be considered to apply regarding permitted transformations.  ("This 
specification does not require support for trap handlers that maintain 
information about the order or count of floating-point exceptions. 
Therefore, between function calls, floating-point exceptions need not be 
precise: the actual order and number of occurrences of floating-point 
exceptions (> 1) may vary from what the source code expresses.")

Logically, there should be a separate option that is a stronger version of 
-ftrapping-math that also prevents global transformations that change 
whether an exception flag is raised between two points where it might be 
observed (e.g. any non-const function call might examine floating-point 
state unless the called function can be seen not to do so, and if non-pure 
might also change that state).  This would affect code movement and dead 
code elimination, for example, and would be needed to fully implement the 
exceptions parts of FENV_ACCESS.

If there were anything supporting trap handlers that determine exactly 
when an exception occurred, as opposed to the standard C model where you 
can test the exception flag bits by calling appropriate fenv.h functions, 
I think that should be yet another option.

It is true that if the execution environment does not support 
floating-point exceptions (flag bits or traps) at all then there are 
various such transformations GCC could apply unconditionally.  (But people 
don't tend to be concerned that much with optimizing floating-point 
performance for soft-float systems, and systems without floating-point 
exceptions are typically soft-float.)
Comment 5 Gabriel Ravier 2021-09-21 00:51:54 UTC
Also of note should be the fact that Clang's current default is `-fno-trapping-math`.

I'm myself kind of curious about how exactly `-ftrapping-math` is interpreted. It certainly doesn't seem to remove every single kind of non-trapping math-based optimization: GCC will remove such statements as `(void)1/x;` even with `-ftrapping-math`, even though that could fault with `x == 0`, and will optimize things like `float x = 3412897421;` to not do a conversion even though that conversion could raise an exception (as 3412897421 cannot be exactly represented as a float), whereas Clang won't do that kind of optimization and will keep those operations as-is.
Comment 6 rguenther@suse.de 2021-09-21 06:36:42 UTC
On Tue, 21 Sep 2021, gabravier at gmail dot com wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54192
> 
> Gabriel Ravier <gabravier at gmail dot com> changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>                  CC|                            |gabravier at gmail dot com
> 
> --- Comment #5 from Gabriel Ravier <gabravier at gmail dot com> ---
> Also of note should be the fact that Clang's current default is
> `-fno-trapping-math`.
> 
> I'm myself kind of curious about how exactly `-ftrapping-math` is interpreted.
> It certainly doesn't seem to remove every single kind of non-trapping
> math-based optimization: GCC will remove such statements as `(void)1/x;` even
> with `-ftrapping-math`, even though that could fault with `x == 0`, and will
> optimize things like `float x = 3412897421;` to not do a conversion even though
> that conversion could raise an exception (as 3412897421 cannot be exactly
> represented as a float), whereas Clang won't do that kind of optimization and
> will keep those operations as-is.

Yes, as said in other contexts GCC happily _removes_ traps if trapping
is the only side-effect.  _Unless_ you also have -fnon-call-exceptions
enabled which is the only way to observe traps.  So we consider
a trap invoking undefined behavior unless you make them well-defined
via -fnon-call-exceptions.

I suppose that argues for a tighter coupling of -fnon-call-exceptions
and -ftrapping-math and in particular not enabling -ftrapping-math
by default (unless -fnon-call-exceptions is enabled?).

Btw, the issue also repeatedly comes up in the context of -ftrapv.

I guess I'll propose a documentation enhancement where we can then
discuss the best way forward.

Note that options like -ftrapv and -ftrapping-math also make GCC
avoid transforms that may turn expressions that do not trap into
expressions that do.  For both that is re-association which can
lead to intermediate integer overflows and intermediate inexact
exception traps.
Comment 7 Eric Botcazou 2021-09-21 07:48:38 UTC
> I suppose that argues for a tighter coupling of -fnon-call-exceptions
> and -ftrapping-math and in particular not enabling -ftrapping-math
> by default (unless -fnon-call-exceptions is enabled?).

Nope, in Ada where -fnon-call-exceptions is the default, -fno-trapping-math is also the default (at least on native platforms).  If you do not do that, then you end up with EH edges from every single floating-point operations.
Comment 8 joseph@codesourcery.com 2021-09-21 20:00:38 UTC
On Tue, 21 Sep 2021, rguenther at suse dot de via Gcc-bugs wrote:

> Yes, as said in other contexts GCC happily _removes_ traps if trapping
> is the only side-effect.  _Unless_ you also have -fnon-call-exceptions
> enabled which is the only way to observe traps.  So we consider
> a trap invoking undefined behavior unless you make them well-defined
> via -fnon-call-exceptions.

That might be relevant to traps in the sense of changing control flow when 
a floating-point exception is signaled.  -fnon-call-exceptions doesn't 
seem very relevant to the -ftrapping-math effects on transformations that 
might affect the set of floating-point exception flags raised by some 
code.  As per my previous comment, -ftrapping-math currently affects (or 
might affect if fully implemented) several different things:

* Disallowing code transformations that cause some code to raise more 
exception flags than it would have before.

* Disallowing code transformations that cause some code to raise fewer 
exception flags than it would have before.

* Ensuring the code generated allows for possible non-local control flow 
from exception traps raised by floating-point operations (this is the part 
where -fnon-call-exceptions might be relevant).

* Disallowing code transformations that might affect whether an exact 
underflow exception occurs in some code (not observable through exception 
flags, is observable through trap handlers).

* Ensuring floating-point operations that might raise exception flags are 
not removed, or moved past code (asms or function calls) that might read 
or modify the exception flag state (not implemented, modulo Marc Glisse's 
-ffenv-access patches from August 2020)
Comment 9 rguenther@suse.de 2021-09-22 06:20:14 UTC
On Tue, 21 Sep 2021, joseph at codesourcery dot com wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54192
> 
> --- Comment #8 from joseph at codesourcery dot com <joseph at codesourcery dot com> ---
> On Tue, 21 Sep 2021, rguenther at suse dot de via Gcc-bugs wrote:
> 
> > Yes, as said in other contexts GCC happily _removes_ traps if trapping
> > is the only side-effect.  _Unless_ you also have -fnon-call-exceptions
> > enabled which is the only way to observe traps.  So we consider
> > a trap invoking undefined behavior unless you make them well-defined
> > via -fnon-call-exceptions.
> 
> That might be relevant to traps in the sense of changing control flow when 
> a floating-point exception is signaled.  -fnon-call-exceptions doesn't 
> seem very relevant to the -ftrapping-math effects on transformations that 
> might affect the set of floating-point exception flags raised by some 
> code.  As per my previous comment, -ftrapping-math currently affects (or 
> might affect if fully implemented) several different things:
> 
> * Disallowing code transformations that cause some code to raise more 
> exception flags than it would have before.
> 
> * Disallowing code transformations that cause some code to raise fewer 
> exception flags than it would have before.

I might add that this particular point isn't followed thoroughly.

> * Ensuring the code generated allows for possible non-local control flow 
> from exception traps raised by floating-point operations (this is the part 
> where -fnon-call-exceptions might be relevant).
> 
> * Disallowing code transformations that might affect whether an exact 
> underflow exception occurs in some code (not observable through exception 
> flags, is observable through trap handlers).
> 
> * Ensuring floating-point operations that might raise exception flags are 
> not removed, or moved past code (asms or function calls) that might read 
> or modify the exception flag state (not implemented, modulo Marc Glisse's 
> -ffenv-access patches from August 2020)

And indeed while the above points are inter-mangled it might make sense
to split -ftrapping-math into controls for the individual exception flag
kinds (-ffinite-math-only overlaps here to some extent), or at least
try to document the effects of the flags we have on the behavior of
the exception state.