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

Reply via email to