On Sun, 23 Jun 2019, Marc Glisse wrote:

> 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 C, initializers with static or thread storage duration always use 
round-to-nearest and discard exceptions (see F.8.2 and F.8.5).  This is 
unaffected by FENV_ACCESS (but *is* affected by FENV_ROUND).

> Note that C2x adds a pragma fenv_round that specifies a rounding direction for
> a region of code, which seems relevant for constant expressions. That pragma
> looks hard, but maybe some pieces would be nice to add.

FENV_ROUND (and FENV_DEC_ROUND) shouldn't be that hard, given the 
optimizers avoiding code movement that doesn't respect rounding modes 
(though I'm only thinking of C here, not C++).  You'd insert appropriate 
built-in function calls to save and restore the dynamic rounding modes in 
scopes with a constant rounding mode set, taking due care about scopes 
being left through goto etc., and restore the mode around calls to 
functions that aren't meant to be affected by the constant rounding modes 
- you'd also need a built-in function to indicate to make a call that is 
affected by the constant rounding modes (and make __builtin_tgmath do that 
as well), and to define all the relevant functions as macros using that 
built-in function in the standard library headers.  Optimizations for 
architectures supporting rounding modes embedded in instructions could 
come later.

Complications would include:

* <float.h> constants should use hex floats to avoid being affected by the 
constant rounding mode (in turn, this may mean disallowing the FENV_ROUND 
pragma in C90 mode because of the lack of hex floats there).  If they use 
decimal rather than hex they'd need to be very long constants to have 
exactly the right value in all rounding modes.

* The built-in functions to change the dynamic rounding mode can't involve 
calling fegetround / fesetround, because those are in libm and libm is not 
supposed to be required unless you call a function in <math.h>, 
<complex.h> or <fenv.h> (simply using a language feature such as a pragma 
should not introduce a libm dependency).  So a similar issue applies as 
applied with atomic compound assignment for floating-point types: every 
target with hardware floating point needs to have its own support for 
expanding those built-in functions inline, and relevant tests will FAIL 
(or be UNSUPPORTED through the compiler calling sorry () when the pragma 
is used) on targets without that support, until it is added.  (And in 
cases where the rounding modes is TLS data in libc rather than in 
hardware, such as soft-float PowerPC GNU/Linux and maybe some other cases 
for DFP, you need new implementation-namespace interfaces there to save / 
restore it.)

-- 
Joseph S. Myers
jos...@codesourcery.com

Reply via email to