sepavloff created this revision. sepavloff added reviewers: rsmith, rjmccall, mibintc. Herald added a project: clang. sepavloff requested review of this revision.
Previously initializers were evaluated using rounding mode currently specified by Sema. If at the same time FP exception behavior was set to `strict`, compiler failed to compile the following C code: struct S { float f; }; static struct S x = {0.63}; This happened because setting strict behavior set rounding mode to `dymanic`. In this case the value of initializer depends on the current rounding mode and it cannot be evaluated in compile time. Initializers for some objects must be constants. On the other hand using `dynamic` as rounding mode make no sense. Even in C++ if the initializer is evaluated dynamically, it happens before execution of `main`, so there is no possibility to set rounding mode for such initializers. So if rounding mode is `dynamic` when an initializer is evaluated in some cases, compiler replaces it with default `tonearest` rounding. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D88498 Files: clang/include/clang/Basic/LangOptions.h clang/include/clang/Sema/Sema.h clang/lib/Parse/ParseDecl.cpp clang/test/AST/const-fpfeatures-diag.c clang/test/AST/const-fpfeatures-strict.c
Index: clang/test/AST/const-fpfeatures-strict.c =================================================================== --- /dev/null +++ clang/test/AST/const-fpfeatures-strict.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -S -emit-llvm -ffp-exception-behavior=strict -Wno-unknown-pragmas %s -o - | FileCheck %s + +// nextUp(1.F) == 0x1.000002p0F + +struct S { + float f; +}; + +static struct S var_01 = {0x1.000001p0}; +struct S *func_01() { + return &var_01; +} + +struct S var_02 = {0x1.000001p0}; + +struct S *func_03() { + static struct S var_03 = {0x1.000001p0}; + return &var_03; +} + +// CHECK: @var_01 = {{.*}} %struct.S { float 1.000000e+00 } +// CHECK: @var_02 = {{.*}} %struct.S { float 1.000000e+00 } +// CHECK: @func_03.var_03 = {{.*}} %struct.S { float 1.000000e+00 } + +#pragma STDC FENV_ROUND FE_UPWARD + +static struct S var_04 = {0x1.000001p0}; +struct S *func_04() { + return &var_04; +} + +struct S var_05 = {0x1.000001p0}; + +struct S *func_06() { + static struct S var_06 = {0x1.000001p0}; + return &var_06; +} + +// CHECK: @var_04 = {{.*}} %struct.S { float 0x3FF0000020000000 } +// CHECK: @var_05 = {{.*}} %struct.S { float 0x3FF0000020000000 } +// CHECK: @func_06.var_06 = {{.*}} %struct.S { float 0x3FF0000020000000 } Index: clang/test/AST/const-fpfeatures-diag.c =================================================================== --- clang/test/AST/const-fpfeatures-diag.c +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clang_cc1 -verify -ffp-exception-behavior=strict -Wno-unknown-pragmas %s - -// REQUIRES: x86-registered-target - -#pragma STDC FENV_ROUND FE_DYNAMIC - -// nextUp(1.F) == 0x1.000002p0F - -float F1 = 0x1.000000p0F + 0x0.000002p0F; -float F2 = 0x1.000000p0F + 0x0.000001p0F; // expected-error{{initializer element is not a compile-time constant}} Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -2281,6 +2281,26 @@ } PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl); + + Sema::FPFeaturesStateRAII FPO(Actions); + if (auto VD = dyn_cast_or_null<VarDecl>(ThisDecl)) + if (!VD->isInvalidDecl()) { + // If variable requires constant initialization, set constant + // rounding mode. + if (VD->isFileVarDecl() || VD->isConstexpr() || + (!getLangOpts().CPlusPlus && VD->isStaticLocal())) { + if (Actions.getCurFPFeatures().getRoundingMode() == + llvm::RoundingMode::Dynamic) { + // If constant rounding mode is 'dynamic', it means that a command + // line option line like `-ffpmodel=strict` is in effect. Set + // constant rounding to default in this case. + FPOptions NewFPO = Actions.getCurFPFeatures(); + NewFPO.setRoundingMode(llvm::RoundingMode::NearestTiesToEven); + Actions.setCurFPFeatures(NewFPO); + } + } + } + ExprResult Init = ParseInitializer(); // If this is the only decl in (possibly) range based for statement, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -589,13 +589,7 @@ // This stack tracks the current state of Sema.CurFPFeatures. PragmaStack<FPOptionsOverride> FpPragmaStack; FPOptionsOverride CurFPFeatureOverrides() { - FPOptionsOverride result; - if (!FpPragmaStack.hasValue()) { - result = FPOptionsOverride(); - } else { - result = FpPragmaStack.CurrentValue; - } - return result; + return FpPragmaStack.CurrentValue; } // RAII object to push / pop sentinel slots for all MS #pragma stacks. @@ -1429,7 +1423,6 @@ const LangOptions &getLangOpts() const { return LangOpts; } OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } - FPOptions &getCurFPFeatures() { return CurFPFeatures; } DiagnosticsEngine &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } @@ -1439,6 +1432,12 @@ ASTMutationListener *getASTMutationListener() const; ExternalSemaSource* getExternalSource() const { return ExternalSource; } + const FPOptions &getCurFPFeatures() const { return CurFPFeatures; } + void setCurFPFeatures(FPOptions FPO) { + FpPragmaStack.CurrentValue = FPOptionsOverride(FPO, CurFPFeatures); + CurFPFeatures = FPO; + } + ///Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -450,6 +450,15 @@ return Opts; } + storage_type getDiffWith(FPOptions FPO) const { + storage_type Diff = 0; +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + if (get##NAME() != FPO.get##NAME()) \ + Diff |= NAME##Mask; +#include "clang/Basic/FPOptions.def" + return Diff; + } + // We can define most of the accessors automatically: #define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ TYPE get##NAME() const { \ @@ -498,6 +507,8 @@ : Options(LO), OverrideMask(OverrideMaskBits) {} FPOptionsOverride(FPOptions FPO) : Options(FPO), OverrideMask(OverrideMaskBits) {} + FPOptionsOverride(FPOptions New, FPOptions Old) + : Options(New), OverrideMask(New.getDiffWith(Old)) {} bool requiresTrailingStorage() const { return OverrideMask != 0; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits