[PATCH] D88498: [FPEnv] Evaluate initializers in constant rounding mode

Serge Pavlov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 30 00:57:56 PDT 2020


sepavloff added inline comments.


================
Comment at: clang/lib/Parse/ParseDecl.cpp:2290
+          // rounding mode.
+          if (VD->isFileVarDecl() || VD->isConstexpr() ||
+              (!getLangOpts().CPlusPlus && VD->isStaticLocal())) {
----------------
rsmith wrote:
> It's far from clear to me that this is correct in C++. In principle, for a dynamic initializer, the rounding mode could have been set by an earlier initializer.
> 
> Perhaps we can make an argument that, due to the permission to interleave initializers from different TUs, every dynamic initializer must leave the program in the default rounding mode, but I don't think even that makes this approach correct, because an initializer could do this:
> 
> ```
> double d;
> double e = (fesetround(...), d = some calculation, fesetround(...default...), d);
> ```
> 
> I think we can only do this in C and will need something different for C++.
> 
> (I think this also has problems in C++ due to constexpr functions: it's not the case that all floating point operations that will be evaluated as part of the initializer lexically appear within it.)
I changed the code to confine it with C and constexpr only. Hopefully this would be enough to enable build of SPECS attempted by @mibintc (https://reviews.llvm.org/D87528#2295015). However in long-term perspective we should return to this code.

The intent was to align behavior of C and C++. If an initializer is valid in C, then it should produce the same code in C++. If the source code like
```
float appx_coeffs_fp32[3 * 256] = {
    SEGMENT_BIAS + 1.4426950216,
…
```
produces compact table in C mode and huge initialization code in C++, it would be strange from user viewpoint and would not give any advantage.

C in C2x presents pretty consistent model, provided that `#pragma STDC FENV_ROUND FE_DYNAMIC` does not set constant rounding mode. Initializers for variables with static allocation are always evaluated in constant rounding mode and user can chose the mode using pragma FENV_ROUND.

When extending this model to C++ we must solve the problem of dynamic initialization. It obviously occurs in runtime rounding mode, so changing between static and dynamic initialization may change semantics. If however dynamic initialization of global variable occurs in constant rounding mode (changing FP control modes in initializers without restoring them is UB), static and dynamic initialization would be semantically equivalent.

We cannot apply the same rule to local static variables, as they are treated differently in C and C++. So the code:
```
float func_01(float x) {
  #pragma STDC FENV_ACCESS ON
  static float val = 1.0/3.0;
  return val;
}
```
Would be compiled differently in C and C++.



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D88498/new/

https://reviews.llvm.org/D88498



More information about the cfe-commits mailing list