[clang] 706e89d - Fix interaction of pragma FENV_ACCESS with other pragmas

Serge Pavlov via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 22 01:15:33 PDT 2022


Author: Serge Pavlov
Date: 2022-06-22T15:13:54+07:00
New Revision: 706e89db97d3dea63dac1ee2c5a26cb2af9651a2

URL: https://github.com/llvm/llvm-project/commit/706e89db97d3dea63dac1ee2c5a26cb2af9651a2
DIFF: https://github.com/llvm/llvm-project/commit/706e89db97d3dea63dac1ee2c5a26cb2af9651a2.diff

LOG: Fix interaction of pragma FENV_ACCESS with other pragmas

Previously `#pragma STDC FENV_ACCESS ON` always set dynamic rounding
mode and strict exception handling. It is not correct in the presence
of other pragmas that also modify rounding mode and exception handling.
For example, the effect of previous pragma FENV_ROUND could be
cancelled, which is not conformant with the C standard. Also
`#pragma STDC FENV_ACCESS OFF` turned off only FEnvAccess flag, leaving
rounding mode and exception handling unchanged, which is incorrect in
general case.

Concrete rounding and exception mode depend on a combination of several
factors like various pragmas and command-line options. During the review
of this patch an idea was proposed that the semantic actions associated
with such pragmas should only set appropriate flags. Actual rounding
mode and exception handling should be calculated taking into account the
state of all relevant options. In such implementation the pragma
FENV_ACCESS should not override properties set by other pragmas but
should set them if such setting is absent.

To implement this approach the following main changes are made:

- Field `FPRoundingMode` is removed from `LangOptions`. Actually there
  are no options that set it to arbitrary rounding mode, the choice was
  only `dynamic` or `tonearest`. Instead, a new boolean flag
  `RoundingMath` is added, with the same meaning as the corresponding
  command-line option.

- Type `FPExceptionModeKind` now has possible value `FPE_Default`. It
  does not represent any particular exception mode but indicates that
  such mode was not set and default value should be used. It allows to
  distinguish the case:

    {
        #pragma STDC FENV_ACCESS ON
	...
    }

  where the pragma must set FPE_Strict, from the case:

    {
        #pragma clang fp exceptions(ignore)
        #pragma STDC FENV_ACCESS ON
        ...
    }

  where exception mode should remain `FPE_Ignore`.

  - Class `FPOptions` has now methods `getRoundingMode` and
  `getExceptionMode`, which calculates the respective properties from
  other specified FP properties.

  - Class `LangOptions` has now methods `getDefaultRoundingMode` and
  `getDefaultExceptionMode`, which calculates default modes from the
  specified options and should be used instead of `getRoundingMode` and
  `getFPExceptionMode` of the same class.

Differential Revision: https://reviews.llvm.org/D126364

Added: 
    

Modified: 
    clang/include/clang/Basic/FPOptions.def
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Basic/LangOptions.h
    clang/include/clang/Driver/Options.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/ExprConstant.cpp
    clang/lib/CodeGen/CGCall.cpp
    clang/lib/CodeGen/CodeGenFunction.cpp
    clang/lib/Frontend/CompilerInstance.cpp
    clang/lib/Parse/ParsePragma.cpp
    clang/lib/Sema/SemaAttr.cpp
    clang/test/AST/ast-dump-fpfeatures.cpp
    clang/test/CodeGen/pragma-fenv_access.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def
index 224c1827144f5..1dfbbb549c874 100644
--- a/clang/include/clang/Basic/FPOptions.def
+++ b/clang/include/clang/Basic/FPOptions.def
@@ -14,9 +14,10 @@
 
 // OPTION(name, type, width, previousName)
 OPTION(FPContractMode, LangOptions::FPModeKind, 2, First)
-OPTION(RoundingMode, LangOptions::RoundingMode, 3, FPContractMode)
-OPTION(FPExceptionMode, LangOptions::FPExceptionModeKind, 2, RoundingMode)
-OPTION(AllowFEnvAccess, bool, 1, FPExceptionMode)
+OPTION(RoundingMath, bool, 1, FPContractMode)
+OPTION(ConstRoundingMode, LangOptions::RoundingMode, 3, RoundingMath)
+OPTION(SpecifiedExceptionMode, LangOptions::FPExceptionModeKind, 2, ConstRoundingMode)
+OPTION(AllowFEnvAccess, bool, 1, SpecifiedExceptionMode)
 OPTION(AllowFPReassociate, bool, 1, AllowFEnvAccess)
 OPTION(NoHonorNaNs, bool, 1, AllowFPReassociate)
 OPTION(NoHonorInfs, bool, 1, NoHonorNaNs)

diff  --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index aa346ba239391..c41b5ddc7fa11 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -311,8 +311,8 @@ COMPATIBLE_LANGOPT(CLFiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined mac
 /// FP_CONTRACT mode (on/off/fast).
 BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type")
 COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating point")
-BENIGN_ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type")
-BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type")
+BENIGN_LANGOPT(RoundingMath, 1, false, "Do not assume default floating-point rounding behavior")
+BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Default, "FP Exception Behavior Mode type")
 BENIGN_ENUM_LANGOPT(FPEvalMethod, FPEvalMethodKind, 2, FEM_UnsetOnCommandLine, "FP type used for floating point arithmetic")
 LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
 LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")

diff  --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index f1b6cb60ae855..78335dabfc88c 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -259,10 +259,6 @@ class LangOptions : public LangOptionsBase {
     FPM_FastHonorPragmas
   };
 
-  /// Alias for RoundingMode::NearestTiesToEven.
-  static constexpr unsigned FPR_ToNearest =
-      static_cast<unsigned>(llvm::RoundingMode::NearestTiesToEven);
-
   /// Possible floating point exception behavior.
   enum FPExceptionModeKind {
     /// Assume that floating-point exceptions are masked.
@@ -270,7 +266,9 @@ class LangOptions : public LangOptionsBase {
     /// Transformations do not cause new exceptions but may hide some.
     FPE_MayTrap,
     /// Strictly preserve the floating-point exception semantics.
-    FPE_Strict
+    FPE_Strict,
+    /// Used internally to represent initial unspecified value.
+    FPE_Default
   };
 
   /// Possible float expression evaluation method choices.
@@ -610,6 +608,18 @@ class LangOptions : public LangOptionsBase {
 
   /// Remap path prefix according to -fmacro-prefix-path option.
   void remapPathPrefix(SmallVectorImpl<char> &Path) const;
+
+  RoundingMode getDefaultRoundingMode() const {
+    return RoundingMath ? RoundingMode::Dynamic
+                        : RoundingMode::NearestTiesToEven;
+  }
+
+  FPExceptionModeKind getDefaultExceptionMode() const {
+    FPExceptionModeKind EM = getFPExceptionMode();
+    if (EM == FPExceptionModeKind::FPE_Default)
+      return FPExceptionModeKind::FPE_Ignore;
+    return EM;
+  }
 };
 
 /// Floating point control options
@@ -617,7 +627,7 @@ class FPOptionsOverride;
 class FPOptions {
 public:
   // We start by defining the layout.
-  using storage_type = uint16_t;
+  using storage_type = uint32_t;
 
   using RoundingMode = llvm::RoundingMode;
 
@@ -646,8 +656,8 @@ class FPOptions {
 public:
   FPOptions() : Value(0) {
     setFPContractMode(LangOptions::FPM_Off);
-    setRoundingMode(static_cast<RoundingMode>(LangOptions::FPR_ToNearest));
-    setFPExceptionMode(LangOptions::FPE_Ignore);
+    setConstRoundingMode(RoundingMode::Dynamic);
+    setSpecifiedExceptionMode(LangOptions::FPE_Default);
   }
   explicit FPOptions(const LangOptions &LO) {
     Value = 0;
@@ -658,8 +668,9 @@ class FPOptions {
     if (LangOptContractMode == LangOptions::FPM_FastHonorPragmas)
       LangOptContractMode = LangOptions::FPM_Fast;
     setFPContractMode(LangOptContractMode);
-    setRoundingMode(LO.getFPRoundingMode());
-    setFPExceptionMode(LO.getFPExceptionMode());
+    setRoundingMath(LO.RoundingMath);
+    setConstRoundingMode(LangOptions::RoundingMode::Dynamic);
+    setSpecifiedExceptionMode(LO.getFPExceptionMode());
     setAllowFPReassociate(LO.AllowFPReassoc);
     setNoHonorNaNs(LO.NoHonorNaNs);
     setNoHonorInfs(LO.NoHonorInfs);
@@ -668,7 +679,7 @@ class FPOptions {
     setAllowApproxFunc(LO.ApproxFunc);
     if (getFPContractMode() == LangOptions::FPM_On &&
         getRoundingMode() == llvm::RoundingMode::Dynamic &&
-        getFPExceptionMode() == LangOptions::FPE_Strict)
+        getExceptionMode() == LangOptions::FPE_Strict)
       // If the FP settings are set to the "strict" model, then
       // FENV access is set to true. (ffp-model=strict)
       setAllowFEnvAccess(true);
@@ -692,10 +703,33 @@ class FPOptions {
 
   bool isFPConstrained() const {
     return getRoundingMode() != llvm::RoundingMode::NearestTiesToEven ||
-           getFPExceptionMode() != LangOptions::FPE_Ignore ||
+           getExceptionMode() != LangOptions::FPE_Ignore ||
            getAllowFEnvAccess();
   }
 
+  RoundingMode getRoundingMode() const {
+    RoundingMode RM = getConstRoundingMode();
+    if (RM == RoundingMode::Dynamic) {
+      // C2x: 7.6.2p3  If the FE_DYNAMIC mode is specified and FENV_ACCESS is
+      // "off", the translator may assume that the default rounding mode is in
+      // effect.
+      if (!getAllowFEnvAccess() && !getRoundingMath())
+        RM = RoundingMode::NearestTiesToEven;
+    }
+    return RM;
+  }
+
+  LangOptions::FPExceptionModeKind getExceptionMode() const {
+    LangOptions::FPExceptionModeKind EM = getSpecifiedExceptionMode();
+    if (EM == LangOptions::FPExceptionModeKind::FPE_Default) {
+      if (getAllowFEnvAccess())
+        return LangOptions::FPExceptionModeKind::FPE_Strict;
+      else
+        return LangOptions::FPExceptionModeKind::FPE_Ignore;
+    }
+    return EM;
+  }
+
   bool operator==(FPOptions other) const { return Value == other.Value; }
 
   /// Return the default value of FPOptions that's used when trailing
@@ -743,7 +777,7 @@ class FPOptionsOverride {
 
   /// The type suitable for storing values of FPOptionsOverride. Must be twice
   /// as wide as bit size of FPOption.
-  using storage_type = uint32_t;
+  using storage_type = uint64_t;
   static_assert(sizeof(storage_type) >= 2 * sizeof(FPOptions::storage_type),
                 "Too short type for FPOptionsOverride");
 

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 5fa681f538194..7aea7324cf241 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1544,7 +1544,7 @@ def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group<
   HelpText<"Specifies the exception behavior of floating-point operations.">,
   Values<"ignore,maytrap,strict">, NormalizedValuesScope<"LangOptions">,
   NormalizedValues<["FPE_Ignore", "FPE_MayTrap", "FPE_Strict"]>,
-  MarshallingInfoEnum<LangOpts<"FPExceptionMode">, "FPE_Ignore">;
+  MarshallingInfoEnum<LangOpts<"FPExceptionMode">, "FPE_Default">;
 defm fast_math : BoolFOption<"fast-math",
   LangOpts<"FastMath">, DefaultFalse,
   PosFlag<SetTrue, [CC1Option], "Allow aggressive, lossy floating-point optimizations",
@@ -1866,7 +1866,7 @@ def fno_honor_infinities : Flag<["-"], "fno-honor-infinities">, Group<f_Group>;
 def : Flag<["-"], "fhonor-infinites">, Alias<fhonor_infinities>;
 def : Flag<["-"], "fno-honor-infinites">, Alias<fno_honor_infinities>;
 def frounding_math : Flag<["-"], "frounding-math">, Group<f_Group>, Flags<[CC1Option]>,
-  MarshallingInfoFlag<LangOpts<"FPRoundingMode">, "llvm::RoundingMode::NearestTiesToEven">,
+  MarshallingInfoFlag<LangOpts<"RoundingMath">>,
   Normalizer<"makeFlagToValueNormalizer(llvm::RoundingMode::Dynamic)">;
 def fno_rounding_math : Flag<["-"], "fno-rounding-math">, Group<f_Group>, Flags<[CC1Option]>;
 def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 12e472a5e4f36..22ebdfe0bfbb4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10311,7 +10311,7 @@ class Sema final {
                                LangOptions::FPExceptionModeKind);
 
   /// Called to set constant rounding mode for floating point operations.
-  void setRoundingMode(SourceLocation Loc, llvm::RoundingMode);
+  void ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode);
 
   /// Called to set exception behavior for floating point operations.
   void setExceptionMode(SourceLocation Loc, LangOptions::FPExceptionModeKind);

diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 65782fbb1eaea..910f943c00adc 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2584,14 +2584,14 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
 
   if ((St != APFloat::opOK) &&
       (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
-       FPO.getFPExceptionMode() != LangOptions::FPE_Ignore ||
+       FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
        FPO.getAllowFEnvAccess())) {
     Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
     return false;
   }
 
   if ((St & APFloat::opStatus::opInvalidOp) &&
-      FPO.getFPExceptionMode() != LangOptions::FPE_Ignore) {
+      FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
     // There is no usefully definable result.
     Info.FFDiag(E);
     return false;

diff  --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 57eb8b2d93d26..735861c83aab2 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1849,7 +1849,7 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
           CodeGenOpts.FP32DenormalMode.str());
     }
 
-    if (LangOpts.getFPExceptionMode() == LangOptions::FPE_Ignore)
+    if (LangOpts.getDefaultExceptionMode() == LangOptions::FPE_Ignore)
       FuncAttrs.addAttribute("no-trapping-math", "true");
 
     // TODO: Are these all needed?

diff  --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 96f36ce2cedd6..2745b0c898ff7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -105,8 +105,9 @@ clang::ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind) {
   case LangOptions::FPE_Ignore:  return llvm::fp::ebIgnore;
   case LangOptions::FPE_MayTrap: return llvm::fp::ebMayTrap;
   case LangOptions::FPE_Strict:  return llvm::fp::ebStrict;
+  default:
+    llvm_unreachable("Unsupported FP Exception Behavior");
   }
-  llvm_unreachable("Unsupported FP Exception Behavior");
 }
 
 void CodeGenFunction::SetFastMathFlags(FPOptions FPFeatures) {
@@ -145,12 +146,11 @@ void CodeGenFunction::CGFPOptionsRAII::ConstructorHelper(FPOptions FPFeatures) {
 
   FMFGuard.emplace(CGF.Builder);
 
-  llvm::RoundingMode NewRoundingBehavior =
-      static_cast<llvm::RoundingMode>(FPFeatures.getRoundingMode());
+  llvm::RoundingMode NewRoundingBehavior = FPFeatures.getRoundingMode();
   CGF.Builder.setDefaultConstrainedRounding(NewRoundingBehavior);
   auto NewExceptionBehavior =
       ToConstrainedExceptMD(static_cast<LangOptions::FPExceptionModeKind>(
-          FPFeatures.getFPExceptionMode()));
+          FPFeatures.getExceptionMode()));
   CGF.Builder.setDefaultConstrainedExcept(NewExceptionBehavior);
 
   CGF.SetFastMathFlags(FPFeatures);
@@ -971,9 +971,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
              (getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>())))
     Fn->addFnAttr(llvm::Attribute::NoRecurse);
 
-  llvm::RoundingMode RM = getLangOpts().getFPRoundingMode();
+  llvm::RoundingMode RM = getLangOpts().getDefaultRoundingMode();
   llvm::fp::ExceptionBehavior FPExceptionBehavior =
-      ToConstrainedExceptMD(getLangOpts().getFPExceptionMode());
+      ToConstrainedExceptMD(getLangOpts().getDefaultExceptionMode());
   Builder.setDefaultConstrainedRounding(RM);
   Builder.setDefaultConstrainedExcept(FPExceptionBehavior);
   if ((FD && (FD->UsesFPIntrin() || FD->hasAttr<StrictFPAttr>())) ||

diff  --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 0ec7964bc5993..b982ca72c78ce 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -123,12 +123,12 @@ bool CompilerInstance::createTarget() {
   }
 
   if (!getTarget().hasStrictFP() && !getLangOpts().ExpStrictFP) {
-    if (getLangOpts().getFPRoundingMode() !=
-        llvm::RoundingMode::NearestTiesToEven) {
+    if (getLangOpts().RoundingMath) {
       getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_rounding);
-      getLangOpts().setFPRoundingMode(llvm::RoundingMode::NearestTiesToEven);
+      getLangOpts().RoundingMath = false;
     }
-    if (getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore) {
+    auto FPExc = getLangOpts().getFPExceptionMode();
+    if (FPExc != LangOptions::FPE_Default && FPExc != LangOptions::FPE_Ignore) {
       getDiagnostics().Report(diag::warn_fe_backend_unsupported_fp_exceptions);
       getLangOpts().setFPExceptionMode(LangOptions::FPE_Ignore);
     }

diff  --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index c94640c31c500..d69081cbecedc 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -804,7 +804,7 @@ void Parser::HandlePragmaFEnvRound() {
       reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
 
   SourceLocation PragmaLoc = ConsumeAnnotationToken();
-  Actions.setRoundingMode(PragmaLoc, RM);
+  Actions.ActOnPragmaFEnvRound(PragmaLoc, RM);
 }
 
 StmtResult Parser::HandlePragmaCaptured()

diff  --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 840aeb2a440eb..8e6f029726bce 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -571,7 +571,7 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
       PP.setCurrentFPEvalMethod(SourceLocation(), PP.getLastFPEvalMethod());
     break;
   case PFC_NoPrecise:
-    if (CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Strict)
+    if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict)
       Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept);
     else if (CurFPFeatures.getAllowFEnvAccess())
       Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv);
@@ -587,11 +587,11 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
     if (!isPreciseFPEnabled())
       Diag(Loc, diag::err_pragma_fc_except_requires_precise);
     else
-      NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
+      NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Strict);
     FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
     break;
   case PFC_NoExcept:
-    NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore);
+    NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Ignore);
     FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
     break;
   case PFC_Push:
@@ -1294,16 +1294,9 @@ void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
   CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
 }
 
-void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) {
-  // C2x: 7.6.2p3  If the FE_DYNAMIC mode is specified and FENV_ACCESS is "off",
-  // the translator may assume that the default rounding mode is in effect.
-  if (FPR == llvm::RoundingMode::Dynamic &&
-      !CurFPFeatures.getAllowFEnvAccess() &&
-      CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Ignore)
-    FPR = llvm::RoundingMode::NearestTiesToEven;
-
+void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) {
   FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
-  NewFPFeatures.setRoundingModeOverride(FPR);
+  NewFPFeatures.setConstRoundingModeOverride(FPR);
   FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
   CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
 }
@@ -1311,14 +1304,13 @@ void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) {
 void Sema::setExceptionMode(SourceLocation Loc,
                             LangOptions::FPExceptionModeKind FPE) {
   FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
-  NewFPFeatures.setFPExceptionModeOverride(FPE);
+  NewFPFeatures.setSpecifiedExceptionModeOverride(FPE);
   FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
   CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
 }
 
 void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
   FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
-  auto LO = getLangOpts();
   if (IsEnabled) {
     // Verify Microsoft restriction:
     // You can't enable fenv_access unless precise semantics are enabled.
@@ -1326,16 +1318,10 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
     // pragma, or by using the /fp:precise or /fp:strict compiler options
     if (!isPreciseFPEnabled())
       Diag(Loc, diag::err_pragma_fenv_requires_precise);
-    NewFPFeatures.setAllowFEnvAccessOverride(true);
-    // Enabling FENV access sets the RoundingMode to Dynamic.
-    // and ExceptionBehavior to Strict
-    NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic);
-    NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
-  } else {
-    NewFPFeatures.setAllowFEnvAccessOverride(false);
   }
+  NewFPFeatures.setAllowFEnvAccessOverride(IsEnabled);
   FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
-  CurFPFeatures = NewFPFeatures.applyOverrides(LO);
+  CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
 }
 
 void Sema::ActOnPragmaFPExceptions(SourceLocation Loc,

diff  --git a/clang/test/AST/ast-dump-fpfeatures.cpp b/clang/test/AST/ast-dump-fpfeatures.cpp
index 70b14ec3b3c0e..8d69b376d9708 100644
--- a/clang/test/AST/ast-dump-fpfeatures.cpp
+++ b/clang/test/AST/ast-dump-fpfeatures.cpp
@@ -87,7 +87,7 @@ float func_10(float x, float y) {
 }
 
 // CHECK-LABEL: FunctionDecl {{.*}} func_10 'float (float, float)'
-// CHECK:         BinaryOperator {{.*}} 'float' '+' RoundingMode=downward
+// CHECK:         BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward
 
 float func_11(float x, float y) {
   if (x < 0) {
@@ -98,8 +98,8 @@ float func_11(float x, float y) {
 }
 
 // CHECK-LABEL: FunctionDecl {{.*}} func_11 'float (float, float)'
-// CHECK:         BinaryOperator {{.*}} 'float' '+' RoundingMode=upward
-// CHECK:         BinaryOperator {{.*}} 'float' '-' RoundingMode=downward
+// CHECK:         BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=upward
+// CHECK:         BinaryOperator {{.*}} 'float' '-' ConstRoundingMode=downward
 
 
 #pragma STDC FENV_ROUND FE_DYNAMIC
@@ -109,7 +109,7 @@ float func_12(float x, float y) {
 }
 
 // CHECK-LABEL: FunctionDecl {{.*}} func_12 'float (float, float)'
-// CHECK:         BinaryOperator {{.*}} 'float' '+' RoundingMode=tonearest
+// CHECK:         BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=dynamic
 
 #pragma STDC FENV_ROUND FE_TONEAREST
 
@@ -118,7 +118,7 @@ float func_13(float x, float y) {
 }
 
 // CHECK-LABEL: FunctionDecl {{.*}} func_13 'float (float, float)'
-// CHECK:         BinaryOperator {{.*}} 'float' '+' RoundingMode=tonearest
+// CHECK:         BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=tonearest
 
 
 template <typename T>
@@ -136,8 +136,8 @@ float func_15(float x, float y) {
 // CHECK:         FunctionDecl {{.*}} func_14 'T (T, T)'
 // CHECK:           CompoundStmt
 // CHECK-NEXT:        ReturnStmt
-// CHECK-NEXT:          BinaryOperator {{.*}} '+' RoundingMode=towardzero
+// CHECK-NEXT:          BinaryOperator {{.*}} '+' ConstRoundingMode=towardzero
 // CHECK:         FunctionDecl {{.*}} func_14 'float (float, float)'
 // CHECK:           CompoundStmt
 // CHECK-NEXT:        ReturnStmt
-// CHECK-NEXT:          BinaryOperator {{.*}} 'float' '+' RoundingMode=towardzero
+// CHECK-NEXT:          BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=towardzero

diff  --git a/clang/test/CodeGen/pragma-fenv_access.c b/clang/test/CodeGen/pragma-fenv_access.c
index 0e2550bcc477d..c986d9cff2a1d 100644
--- a/clang/test/CodeGen/pragma-fenv_access.c
+++ b/clang/test/CodeGen/pragma-fenv_access.c
@@ -1,5 +1,15 @@
-// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - -fms-extensions -DMS | FileCheck %s
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,STRICT %s
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - -fms-extensions -DMS | FileCheck --check-prefixes=CHECK,STRICT %s
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,DEFAULT %s
+
+
+float func_00(float x, float y) {
+  return x + y;
+}
+// CHECK-LABEL: @func_00
+// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// DEFAULT: fadd float
+
 
 #ifdef MS
 #pragma fenv_access (on)
@@ -20,7 +30,7 @@ float func_02(float x, float y) {
   return x + y;
 }
 // CHECK-LABEL: @func_02
-// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
 
 
 float func_03(float x, float y) {
@@ -41,7 +51,16 @@ float func_04(float x, float y) {
   return x + y;
 }
 // CHECK-LABEL: @func_04
-// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// DEFAULT: fadd float
+
+
+float func_04a(float x, float y) {
+  #pragma float_control(except, on)
+  return x + y;
+}
+// CHECK-LABEL: @func_04a
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
 
 
 float func_05(float x, float y) {
@@ -57,18 +76,151 @@ float func_06(float x, float y) {
   return x + y;
 }
 // CHECK-LABEL: @func_06
-// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// DEFAULT: fadd float
 
 
 float func_07(float x, float y) {
   x -= y;
   if (x) {
     #pragma STDC FENV_ACCESS ON
-    y *= 2;
+    y *= 2.0F;
   }
-  return y + 4;
+  return y + 4.0F;
 }
 // CHECK-LABEL: @func_07
-// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
-// CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// STRICT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// STRICT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// DEFAULT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+
+
+float func_08(float x, float y) {
+  #pragma STDC FENV_ROUND FE_UPWARD
+  #pragma STDC FENV_ACCESS ON
+  return x + y;
+}
+// CHECK-LABEL: @func_08
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+
+
+float func_09(float x, float y) {
+  #pragma STDC FENV_ROUND FE_TONEAREST
+  #pragma STDC FENV_ACCESS ON
+  return x + y;
+}
+// CHECK-LABEL: @func_09
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+
+
+float func_10(float x, float y) {
+  #pragma STDC FENV_ROUND FE_TONEAREST
+  #pragma clang fp exceptions(ignore)
+  #pragma STDC FENV_ACCESS ON
+  return x + y;
+}
+// CHECK-LABEL: @func_10
+// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+
+
+float func_11(float x, float y) {
+  #pragma STDC FENV_ROUND FE_TONEAREST
+  #pragma clang fp exceptions(ignore)
+  #pragma STDC FENV_ACCESS OFF
+  return x + y;
+}
+// CHECK-LABEL: @func_11
+// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// DEFAULT: fadd float
+
+
+float func_12(float x, float y) {
+  #pragma clang fp exceptions(maytrap)
+  #pragma STDC FENV_ACCESS ON
+  return x + y;
+}
+// CHECK-LABEL: @func_12
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+
+
+float func_13(float x, float y) {
+  #pragma clang fp exceptions(maytrap)
+  #pragma STDC FENV_ROUND FE_UPWARD
+  #pragma STDC FENV_ACCESS ON
+  return x + y;
+}
+// CHECK-LABEL: @func_13
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+
+
+float func_14(float x, float y, float z) {
+  #pragma STDC FENV_ACCESS ON
+  float res = x * y;
+  {
+    #pragma STDC FENV_ACCESS OFF
+    return res + z;
+  }
+}
+// CHECK-LABEL: @func_14
+// STRICT:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// STRICT:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+
+
+float func_15(float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  #pragma STDC FENV_ACCESS ON
+  float res = x * y;
+  {
+    #pragma STDC FENV_ACCESS OFF
+    return res + z;
+  }
+}
+// CHECK-LABEL: @func_15
+// STRICT:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+// STRICT:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+
+
+float func_16(float x, float y) {
+  x -= y;
+  {
+    #pragma STDC FENV_ROUND FE_TONEAREST
+    #pragma STDC FENV_ACCESS ON
+    y *= 2.0F;
+  }
+  {
+    #pragma STDC FENV_ACCESS ON
+    return y + 4.0F;
+  }
+}
+// CHECK-LABEL: @func_16
+// STRICT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// STRICT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// DEFAULT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// DEFAULT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+
+
+float func_17(float x, float y) {
+  #pragma STDC FENV_ROUND FE_DYNAMIC
+  #pragma STDC FENV_ACCESS ON
+  return x + y;
+}
+// CHECK-LABEL: @func_17
 // CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+
+
+float func_18(float x, float y) {
+  #pragma STDC FENV_ROUND FE_DYNAMIC
+  return x + y;
+}
+// CHECK-LABEL: @func_18
+// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// DEFAULT: fadd float
+


        


More information about the cfe-commits mailing list