rsmith added inline comments.

================
Comment at: clang/lib/Parse/ParseDecl.cpp:2290
+          // rounding mode.
+          if (VD->isFileVarDecl() || VD->isConstexpr() ||
+              (!getLangOpts().CPlusPlus && VD->isStaticLocal())) {
----------------
mibintc wrote:
> sepavloff wrote:
> > sepavloff wrote:
> > > 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++.
> > > 
> > Additional note:
> > 
> > If initialization is dynamic and constant rounding mode is not default, the 
> > body of initializer is executed with dynamic rounding mode set to the 
> > constant mode. That is, the code:
> > ```
> >     #pragma STDC FENV_ROUND FE_UPWARD
> >     float var = some_init_expr;
> > ```
> > generates code similar to:
> > ```
> >     float var = []()->float {
> >       #pragma STDC FENV_ROUND FE_UPWARD
> >       return some_init_expr;
> >     }
> > ```
> > 
> > So initializers of global variable must conform to:
> > 
> > 1. If the initialization is dynamic and dynamic rounding mode is changed in 
> > the initializer, it must be restored upon finishing the initializer.
> > 2. The initializer is evaluated in constant rounding mode. If the 
> > initialization is dynamic, the initializing code is executed in dynamic 
> > rounding mode set to the constant rounding mode.
> > 
> > These seems enough to provide compatibility with C and the same semantics 
> > for static and dynamic initialization.
> @rsmith Serge changed the patch to confine it with C and constexpr only, is 
> that adequate to move forward with this patch, and we can return to C++ at 
> some point down the road?
This still seems inappropriate for the `constexpr` case -- we shouldn't have 
different behavior based on whether an expression appears directly in the 
initializer or in a `constexpr` function invoked by that initializer. (It also 
violates the C++ standard's recommendation that floating-point evaluation 
during translation and at runtime produce the same value.) Please see the 
discussion in D87528. Let's continue the conversation there; we shouldn't be 
splitting this discussion across two separate review threads.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88498

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to