On Mon, 24 Jun 2019, Szabolcs Nagy wrote:
On 22/06/2019 23:21, Marc Glisse wrote:
We should care about the C standard, and do whatever makes sense for C++
without expecting the C++ standard to tell us exactly what that is. We
can check what visual studio and intel do, but we don't have to follow them.
-frounding-math is supposed to be equivalent to "#pragma stdc fenv_access on"
covering the whole program.
i think there are 4 settings that make sense:
(i think function level granularity is ok for
this, iso c has block scope granularity, gcc
has translation unit level granularity.)
(1) except flags + only caller observes it.
i.e. exception flags raised during the execution
of the function matter, but only the caller
observes the flags by checking them.
(2) rounding mode + only caller changes it.
i.e. rounding mode may not be the default during
the execution of the function, but only the
caller may change the rounding mode.
(3) except flags + anything may observe/unset it.
i.e. exception flags raised during the execution
of the function matter, and any call or inline
asm may observe or unset them (unless the
compiler can prove otherwise).
(4) rounding mode + anything may change it.
i.e. rounding mode may not be the default or
change during the execution of a function,
and any call or inline asm may change it.
i think -frounding-math implements (2) fairly reliably,
I hadn't thought of it that way, but it is true that this is fairly well
handled. I could possibly use this in some places in CGAL, using a wrapper
so I can specify noinline/noipa at the call site. I'll have to experiment.
In particular it means that if I use -frounding-math to enable (4), there
are valid uses where it will cause a speed regression :-(
and #pragma stdc fenv_access on requires (3) and (4).
-ftrapping-math was never clear, but it should
probably do (1) or (5) := (3)+"exceptions may trap".
so iso c has 2 levels: fenv access on/off, where
"on" means that essentially everything has to be
compiled with (3) and (4) (even functions that
don't do anything with fenv). this is not very
practical: most extern calls don't modify the fenv
so fp operations can be reordered around them,
(1) and (2) are more relaxed about this, however
that model needs fp barriers around the few calls
that actually does fenv access.
to me (1) + (2) + builtins for fp barriers seems
more useful than iso c (3) + (4), but iso c is
worth implementing too, since that's the standard.
so ideally there would be multiple flags/function
attributes and builtin barriers to make fenv access
usable in practice. (however not many things care
about fenv access so i don't know if that amount
of work is justifiable).
That makes sense. If we got (4), the interest for (2) would depend a lot
on the speed difference. If the difference is small enough, then having
only (4) might suffice. But at least separating rounding from exception
flags seems good.
Depending on how we change things, it could be nice to add to the
decription of -frounding-math the precision you gave above (only the
caller may change it).
For constant expressions, I see a difference between
constexpr double third = 1. / 3.;
which really needs to be done at compile time, and
const double third = 1. / 3.;
which will try to evaluate the rhs as constexpr, but where the program is still
valid if that fails. The second one clearly should refuse to be
evaluated at compile time if we are specifying a dynamic rounding direction.
For the first one, I am not sure. I guess you should only write
that in "fenv_access off" regions and I wouldn't mind a compile error.
iso c specifies rules for const expressions:
http://port70.net/~nsz/c/c11/n1570.html#F.8.4
static/thread storage duration is evaluated with
default rounding mode and no exceptions are signaled.
other initialization is evaluated at runtime.
(i.e. rounding-mode dependent result and
exception flags are observable).
Thanks for the reference.
--
Marc Glisse