jcranmer-intel wrote:

The topic is a little difficult to broach to the C/C++ committees because it's 
an interaction of aspects of each language that the other committee doesn't 
want to talk about for the most part, so you end up having to interpolate 
general design guidelines to figure out what to do.

> If the rounding mode is dynamic (and `FENV_ACCESS` is "on"), it is only 
> acceptable to fold cases that are not manifestly constant-evaluated if the 
> result is exact.

The basic rule in C is that all floating-point operations "as if" at execution 
time unless they can't be done at execution time. Interpolating that to C++ 
semantics, then all floating-point operations are "as if" at execution time 
unless manifestly constant-evaluated.

Frontend-level constant folding of not manifestly constant-evaluated 
expressions can happen only if happening at translation time is not observable, 
meaning:
- If `FENV_ACCESS` is off and `FENV_ROUND` is missing, we are in the fully 
default FP environments. FP exceptions are not visible, no funky control bits 
are set, and the rounding mode is default. It is safe to do the translation at 
compile-time.
- If `FENV_ACCESS` is off and `FENV_ROUND` is present, then we are in the fully 
default FP environment except that the rounding mode isn't necessarily in the 
default rounding mode. We can do the translation at compile-time, even if 
`FENV_ROUND` is `FE_DYNAMIC` (since the translator is explicitly allowed to 
assume that it's in the default round per the C specification).
- If `FENV_ACCESS` is on and `FENV_ROUND` is missing, we are in an arbitrary FP 
environment. FP exceptions are visible, funky control bits may be set, and the 
rounding mode may be in any state. It is not safe to do the translation at 
compile-time, since we cannot guarantee that a weird control bit (like x87 
precision control) is not in play.
- If `FENV_ACCESS` is on and `FENV_ROUND` is present, then we at least know the 
rounding mode. But since we still can't assume the absence of funky control 
bits, it's not safe to do the translation at compile-time.

Because of the potential for funky control bits, I lean towards the stance of 
prohibiting non-mandatory constant evaluation of floating-point expressions 
when `FENV_ACCESS` is on, even if the expression would be exact. But 
`FENV_ACCESS` being off lets us exercise the as-if rule pretty freely.

> `FENV_ROUND` is specified, by the C standard, to affect the behaviour of 
> `fma` by means of macro replacement: a call that avoids the macro 
> replacement, e.g., `(fma)(x, y, z)` is supposed to operate using the dynamic 
> rounding mode.

The C standard doesn't discuss the behavior of `__builtin_fma`, so we have to 
interpolate what its behavior should be from the more general rules of 
`FENV_ROUND`. The way I read the intent is that `FENV_ROUND` applies the 
behavior of the rounding mode to all known operations and restores the dynamic 
rounding mode for all unknown function calls, with standard library calls being 
considered to be a known operation when they are not macro-replaced.

> As for manifestly constant-evaluated contexts, we do expect rounding to 
> occur; however, whether the default rounding mode or the "constant rounding 
> mode" should be used is a matter of design that should be backed by 
> documentation. The documentation actively suggests that the default rounding 
> mode is used: 
> https://releases.llvm.org/21.1.0/tools/clang/docs/UsersManual.html#cmdoption-f-no-rounding-math.

That documentation appears to have been written in 2019 and not updated since 
then, which is before `FENV_ROUND` was incorporated into C2x, long before any 
work was done in Clang to support `FENV_ROUND`. Especially as Clang's 
`FENV_ROUND` implementation is still incomplete enough that we don't claim to 
support it yet, I wouldn't take it as any definitive evidence of a decision 
having been made.


To my mind, the most defensible behavior for `__builtin_fma` (and future 
similar builtins) is this: they have the same behavior with respect to constant 
expression evaluation, rounding mode, and strict FP mode (i.e., `FENV_ACCESS`) 
as a humble `+` operator. That is, in the cases where they are manifestly 
constant-evaluated, they take on the rounding mode implied by `FENV_ROUND`.


https://github.com/llvm/llvm-project/pull/158048
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to