[clang] 4bafe65 - Add support for floating-point option `ffp-eval-method` and for

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 15 13:59:35 PST 2022


Author: Zahira Ammarguellat
Date: 2022-02-15T13:59:27-08:00
New Revision: 4bafe65c2b2f1ce745894a509a6d80c87fb1c335

URL: https://github.com/llvm/llvm-project/commit/4bafe65c2b2f1ce745894a509a6d80c87fb1c335
DIFF: https://github.com/llvm/llvm-project/commit/4bafe65c2b2f1ce745894a509a6d80c87fb1c335.diff

LOG: Add support for floating-point option `ffp-eval-method` and for
`pragma clang fp eval_method`.

Added: 
    clang/test/CodeGen/X86/32bit-behavior-no-eval.c
    clang/test/CodeGen/X86/32bit-behavior.c
    clang/test/CodeGen/X86/fp-eval-method.c
    clang/test/CodeGen/flt_eval_macro.cpp
    clang/test/Preprocessor/flt_eval_macro.cpp
    clang/test/Sema/fp-eval-pragma.cpp
    clang/test/Sema/x86-eval-method.c
    clang/test/Sema/x86_64-eval-method.c

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/docs/UsersManual.rst
    clang/include/clang/Basic/DiagnosticCommonKinds.td
    clang/include/clang/Basic/DiagnosticLexKinds.td
    clang/include/clang/Basic/FPOptions.def
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Basic/LangOptions.h
    clang/include/clang/Basic/TargetInfo.h
    clang/include/clang/Driver/Options.td
    clang/include/clang/Lex/Preprocessor.h
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/Sema.h
    clang/lib/Basic/Targets/OSTargets.h
    clang/lib/Basic/Targets/X86.h
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Frontend/InitPreprocessor.cpp
    clang/lib/Lex/PPMacroExpansion.cpp
    clang/lib/Parse/ParsePragma.cpp
    clang/lib/Parse/ParseStmt.cpp
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaAttr.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/test/CodeGen/fp-floatcontrol-pragma.cpp
    clang/test/Preprocessor/init-aarch64.c
    clang/test/Preprocessor/init-arm.c
    clang/test/Preprocessor/init-mips.c
    clang/test/Preprocessor/init-ppc.c
    clang/test/Preprocessor/init-ppc64.c
    clang/test/Preprocessor/init-s390x.c
    clang/test/Preprocessor/init-v7k-compat.c
    clang/test/Preprocessor/init-x86.c
    clang/test/Preprocessor/init.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index f45d88092eb4a..5249d3f3f7930 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3907,6 +3907,38 @@ A ``#pragma clang fp`` pragma may contain any number of options:
     ...
   }
 
+``#pragma clang fp eval_method`` allows floating-point behavior to be specified
+for a section of the source code. This pragma can appear at file or namespace
+scope, or at the start of a compound statement (excluding comments).
+The pragma is active within the scope of the compound statement.
+
+When ``pragma clang fp eval_method(source)`` is enabled, the section of code
+governed by the pragma behaves as though the command-line option
+``-ffp-eval-method=source`` is enabled. Rounds intermediate results to
+source-defined precision.
+
+When ``pragma clang fp eval_method(double)`` is enabled, the section of code
+governed by the pragma behaves as though the command-line option
+``-ffp-eval-method=double`` is enabled. Rounds intermediate results to
+``double`` precision.
+
+When ``pragma clang fp eval_method(extended)`` is enabled, the section of code
+governed by the pragma behaves as though the command-line option
+``-ffp-eval-method=extended`` is enabled. Rounds intermediate results to
+target-dependent ``long double`` precision. In Win32 programming, for instance,
+the long double data type maps to the double, 64-bit precision data type.
+
+The full syntax this pragma supports is
+``#pragma clang fp eval_method(source|double|extended)``.
+
+.. code-block:: c++
+
+  for(...) {
+    // The compiler will use long double as the floating-point evaluation
+    // method.
+    #pragma clang fp eval_method(extended)
+    a = b[i] * c[i] + e;
+  }
 
 The ``#pragma float_control`` pragma allows precise floating-point
 semantics and floating-point exception behavior to be specified

diff  --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 1df96296cb8ac..70fee29ab2a84 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1566,6 +1566,22 @@ Note that floating-point operations performed as part of constant initialization
    * ``maytrap`` The compiler avoids transformations that may raise exceptions that would not have been raised by the original code. Constant folding performed by the compiler is exempt from this option.
    * ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code.
 
+.. option:: -ffp-eval-method=<value>
+
+   Specify the floating-point evaluation method for intermediate results within
+   a single expression of the code.
+
+   Valid values are: ``source``, ``double``, and ``extended``.
+   For 64-bit targets, the default value is ``source``. For 32-bit x86 targets
+   however, in the case of NETBSD 6.99.26 and under, the default value is
+   ``double``; in the case of NETBSD greater than 6.99.26, with NoSSE, the
+   default value is ``extended``, with SSE the default value is ``source``.
+   Details:
+
+   * ``source`` The compiler uses the floating-point type declared in the source program as the evaluation method.
+   * ``double`` The compiler uses ``double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``double``.
+   * ``extended`` The compiler uses ``long double`` as the floating-point evaluation method for all float expressions of type that is narrower than ``long double``.
+
 .. option:: -f[no-]protect-parens:
 
    This option pertains to floating-point types, complex types with
@@ -1587,6 +1603,17 @@ Note that floating-point operations performed as part of constant initialization
    has no effect because the optimizer is prohibited from making unsafe
    transformations.
 
+.. _FLT_EVAL_METHOD:
+
+A note about ``__FLT_EVAL_METHOD__``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The macro ``__FLT_EVAL_METHOD__`` will expand to either the value set from the
+command line option ``ffp-eval-method`` or to the value from the target info
+setting. The ``__FLT_EVAL_METHOD__`` macro cannot expand to the correct
+evaluation method in the presence of a ``#pragma`` which alters the evaluation
+method. An error is issued if ``__FLT_EVAL_METHOD__`` is expanded inside a scope
+modified by ``#pragma clang fp eval_method``.
+
 .. _fp-constant-eval:
 
 A note about Floating Point Constant Evaluation

diff  --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 421527827a4bd..bbf26d637265e 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -318,6 +318,11 @@ def err_opt_not_valid_on_target : Error<
 def err_invalid_feature_combination : Error<
   "invalid feature combination: %0">;
 
+// Eval method
+def warn_no_support_for_eval_method_source_on_m32 : Warning<
+  "Setting FPEvalMethod to source on a 32bit target, with no SSE is"
+  " not supported.">;
+
 // Source manager
 def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
 def err_file_modified : Error<

diff  --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index a4436208799f9..0f424b02c812a 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -321,6 +321,10 @@ def err_pragma_include_instead_system_reserved : Error<
   "header '%0' is an implementation detail; #include %select{'%2'|either '%2' "
   "or '%3'|one of %2}1 instead">;
 
+def err_illegal_use_of_flt_eval_macro : Error<
+  "'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing "
+  "'#pragma clang fp eval_method'">;
+
 def pp_poisoning_existing_macro : Warning<"poisoning existing macro">;
 def pp_out_of_date_dependency : Warning<
   "current file is older than dependency %0">;

diff  --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def
index a93fa475cd5f6..224c1827144f5 100644
--- a/clang/include/clang/Basic/FPOptions.def
+++ b/clang/include/clang/Basic/FPOptions.def
@@ -23,4 +23,5 @@ OPTION(NoHonorInfs, bool, 1, NoHonorNaNs)
 OPTION(NoSignedZero, bool, 1, NoHonorInfs)
 OPTION(AllowReciprocal, bool, 1, NoSignedZero)
 OPTION(AllowApproxFunc, bool, 1, AllowReciprocal)
+OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
 #undef OPTION

diff  --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 4651f4fff6aa0..89b11fdea89b2 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -301,6 +301,7 @@ BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contracti
 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_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")
 LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")

diff  --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 50c7f038fc6be..2e334e375950e 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -235,6 +235,24 @@ class LangOptions : public LangOptionsBase {
     FPE_Strict
   };
 
+  /// Possible float expression evaluation method choices.
+  enum FPEvalMethodKind {
+    /// The evaluation method cannot be determined or is inconsistent for this
+    /// target.
+    FEM_Indeterminable = -1,
+    /// Use the declared type for fp arithmetic.
+    FEM_Source = 0,
+    /// Use the type double for fp arithmetic.
+    FEM_Double = 1,
+    /// Use extended type for fp arithmetic.
+    FEM_Extended = 2,
+    /// Used only for FE option processing; this is only used to indicate that
+    /// the user did not specify an explicit evaluation method on the command
+    /// line and so the target should be queried for its default evaluation
+    /// method instead.
+    FEM_UnsetOnCommandLine = 3
+  };
+
   /// Possible exception handling behavior.
   enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm };
 

diff  --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 22918f7e12e84..8e18ded7d3765 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -726,7 +726,11 @@ class TargetInfo : public virtual TransferrableTargetInfo,
   }
 
   /// Return the value for the C99 FLT_EVAL_METHOD macro.
-  virtual unsigned getFloatEvalMethod() const { return 0; }
+  virtual LangOptions::FPEvalMethodKind getFPEvalMethod() const {
+    return LangOptions::FPEvalMethodKind::FEM_Source;
+  }
+
+  virtual bool supportSourceEvalMethod() const { return true; }
 
   // getLargeArrayMinWidth/Align - Return the minimum array size that is
   // 'large' and its alignment.

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index b81973155cae6..f1e8b967c78e5 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1495,6 +1495,11 @@ def : Flag<["-"], "fextended-identifiers">, Group<clang_ignored_f_Group>;
 def : Flag<["-"], "fno-extended-identifiers">, Group<f_Group>, Flags<[Unsupported]>;
 def fhosted : Flag<["-"], "fhosted">, Group<f_Group>;
 def fdenormal_fp_math_EQ : Joined<["-"], "fdenormal-fp-math=">, Group<f_Group>, Flags<[CC1Option]>;
+def ffp_eval_method_EQ : Joined<["-"], "ffp-eval-method=">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Specifies the evaluation method to use for floating-point arithmetic.">,
+  Values<"source,double,extended">, NormalizedValuesScope<"LangOptions">,
+  NormalizedValues<["FEM_Source", "FEM_Double", "FEM_Extended"]>,
+  MarshallingInfoEnum<LangOpts<"FPEvalMethod">, "FEM_UnsetOnCommandLine">;
 def ffp_model_EQ : Joined<["-"], "ffp-model=">, Group<f_Group>, Flags<[NoXarchOption]>,
   HelpText<"Controls the semantics of floating-point calculations.">;
 def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group<f_Group>, Flags<[CC1Option]>,

diff  --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 2802329a60220..f2c84e43ddca3 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -179,12 +179,27 @@ class Preprocessor {
   IdentifierInfo *Ident__is_target_vendor;         // __is_target_vendor
   IdentifierInfo *Ident__is_target_os;             // __is_target_os
   IdentifierInfo *Ident__is_target_environment;    // __is_target_environment
+  IdentifierInfo *Ident__FLT_EVAL_METHOD__;        // __FLT_EVAL_METHOD
 
   // Weak, only valid (and set) while InMacroArgs is true.
   Token* ArgMacro;
 
   SourceLocation DATELoc, TIMELoc;
 
+  // FEM_UnsetOnCommandLine means that an explicit evaluation method was
+  // not specified on the command line. The target is queried to set the
+  // default evaluation method.
+  LangOptions::FPEvalMethodKind CurrentFPEvalMethod =
+      LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine;
+
+  // The most recent pragma location where the floating point evaluation
+  // method was modified. This is used to determine whether the
+  // 'pragma clang fp eval_method' was used whithin the current scope.
+  SourceLocation LastFPEvalPragmaLocation;
+
+  LangOptions::FPEvalMethodKind TUFPEvalMethod =
+      LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine;
+
   // Next __COUNTER__ value, starts at 0.
   unsigned CounterValue = 0;
 
@@ -2048,6 +2063,32 @@ class Preprocessor {
   unsigned getCounterValue() const { return CounterValue; }
   void setCounterValue(unsigned V) { CounterValue = V; }
 
+  LangOptions::FPEvalMethodKind getCurrentFPEvalMethod() const {
+    assert(CurrentFPEvalMethod != LangOptions::FEM_UnsetOnCommandLine &&
+           "FPEvalMethod should be set either from command line or from the "
+           "target info");
+    return CurrentFPEvalMethod;
+  }
+
+  LangOptions::FPEvalMethodKind getTUFPEvalMethod() const {
+    return TUFPEvalMethod;
+  }
+
+  SourceLocation getLastFPEvalPragmaLocation() const {
+    return LastFPEvalPragmaLocation;
+  }
+
+  void setCurrentFPEvalMethod(SourceLocation PragmaLoc,
+                              LangOptions::FPEvalMethodKind Val) {
+    assert(Val != LangOptions::FEM_UnsetOnCommandLine &&
+           "FPEvalMethod should never be set to FEM_UnsetOnCommandLine");
+    // This is the location of the '#pragma float_control" where the
+    // execution state is modifed.
+    LastFPEvalPragmaLocation = PragmaLoc;
+    CurrentFPEvalMethod = Val;
+    TUFPEvalMethod = Val;
+  }
+
   /// Retrieves the module that we're currently building, if any.
   Module *getCurrentModule();
 

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 981800a7e2356..d2e588992238d 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -184,6 +184,7 @@ class Parser : public CodeCompletionHandler {
   std::unique_ptr<PragmaHandler> PCSectionHandler;
   std::unique_ptr<PragmaHandler> MSCommentHandler;
   std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
+  std::unique_ptr<PragmaHandler> FPEvalMethodHandler;
   std::unique_ptr<PragmaHandler> FloatControlHandler;
   std::unique_ptr<PragmaHandler> MSPointersToMembers;
   std::unique_ptr<PragmaHandler> MSVtorDisp;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c1e846c55dee7..60ee577fca06a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1541,19 +1541,16 @@ class Sema final {
   /// statements.
   class FPFeaturesStateRAII {
   public:
-    FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.CurFPFeatures) {
-      OldOverrides = S.FpPragmaStack.CurrentValue;
-    }
-    ~FPFeaturesStateRAII() {
-      S.CurFPFeatures = OldFPFeaturesState;
-      S.FpPragmaStack.CurrentValue = OldOverrides;
-    }
+    FPFeaturesStateRAII(Sema &S);
+    ~FPFeaturesStateRAII();
     FPOptionsOverride getOverrides() { return OldOverrides; }
 
   private:
     Sema& S;
     FPOptions OldFPFeaturesState;
     FPOptionsOverride OldOverrides;
+    LangOptions::FPEvalMethodKind OldEvalMethod;
+    SourceLocation OldFPPragmaLocation;
   };
 
   void addImplicitTypedef(StringRef Name, QualType T);
@@ -10131,6 +10128,9 @@ class Sema final {
            !CurFPFeatures.getAllowApproxFunc();
   }
 
+  void ActOnPragmaFPEvalMethod(SourceLocation Loc,
+                               LangOptions::FPEvalMethodKind Value);
+
   /// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control
   void ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action,
                                PragmaFloatControlKind Value);

diff  --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h
index 3c1830d5f8e89..f61652d285a89 100644
--- a/clang/lib/Basic/Targets/OSTargets.h
+++ b/clang/lib/Basic/Targets/OSTargets.h
@@ -749,7 +749,9 @@ class AIXTargetInfo : public OSTargetInfo<Target> {
   }
 
   // AIX sets FLT_EVAL_METHOD to be 1.
-  unsigned getFloatEvalMethod() const override { return 1; }
+  LangOptions::FPEvalMethodKind getFPEvalMethod() const override {
+    return LangOptions::FPEvalMethodKind::FEM_Double;
+  }
 
   bool defaultsToAIXPowerAlignment() const override { return true; }
 };

diff  --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index d1b66432e38b4..e0bb3c344c5b6 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -168,11 +168,15 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
     return LongDoubleFormat == &llvm::APFloat::IEEEquad() ? "g" : "e";
   }
 
-  unsigned getFloatEvalMethod() const override {
+  LangOptions::FPEvalMethodKind getFPEvalMethod() const override {
     // X87 evaluates with 80 bits "long double" precision.
-    return SSELevel == NoSSE ? 2 : 0;
+    return SSELevel == NoSSE ? LangOptions::FPEvalMethodKind::FEM_Extended
+                             : LangOptions::FPEvalMethodKind::FEM_Source;
   }
 
+  // EvalMethod `source` is not supported for targets with `NoSSE` feature.
+  bool supportSourceEvalMethod() const override { return SSELevel > NoSSE; }
+
   ArrayRef<const char *> getGCCRegNames() const override;
 
   ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
@@ -471,13 +475,13 @@ class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
   NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
       : NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}
 
-  unsigned getFloatEvalMethod() const override {
+  LangOptions::FPEvalMethodKind getFPEvalMethod() const override {
     VersionTuple OsVersion = getTriple().getOSVersion();
     // New NetBSD uses the default rounding mode.
     if (OsVersion >= VersionTuple(6, 99, 26) || OsVersion.getMajor() == 0)
-      return X86_32TargetInfo::getFloatEvalMethod();
+      return X86_32TargetInfo::getFPEvalMethod();
     // NetBSD before 6.99.26 defaults to "double" rounding.
-    return 1;
+    return LangOptions::FPEvalMethodKind::FEM_Double;
   }
 };
 

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 945f626977799..ee32e5849ff84 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2719,6 +2719,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
   StringRef FPModel = "";
   // -ffp-exception-behavior options: strict, maytrap, ignore
   StringRef FPExceptionBehavior = "";
+  // -ffp-eval-method options: double, extended, source
+  StringRef FPEvalMethod = "";
   const llvm::DenormalMode DefaultDenormalFPMath =
       TC.getDefaultDenormalModeForType(Args, JA);
   const llvm::DenormalMode DefaultDenormalFP32Math =
@@ -2914,6 +2916,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
       break;
     }
 
+    // Validate and pass through -ffp-eval-method option.
+    case options::OPT_ffp_eval_method_EQ: {
+      StringRef Val = A->getValue();
+      if (Val.equals("double") || Val.equals("extended") ||
+          Val.equals("source"))
+        FPEvalMethod = Val;
+      else
+        D.Diag(diag::err_drv_unsupported_option_argument)
+            << A->getOption().getName() << Val;
+      break;
+    }
+
     case options::OPT_ffinite_math_only:
       HonorINFs = false;
       HonorNaNs = false;
@@ -3069,6 +3083,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
     CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" +
                       FPExceptionBehavior));
 
+  if (!FPEvalMethod.empty())
+    CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" + FPEvalMethod));
+
   ParseMRecip(D, Args, CmdArgs);
 
   // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the

diff  --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index bf8a0b2abe22e..ff507e2c00aaa 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -1136,7 +1136,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
   }
 
   // Macros to control C99 numerics and <float.h>
-  Builder.defineMacro("__FLT_EVAL_METHOD__", Twine(TI.getFloatEvalMethod()));
   Builder.defineMacro("__FLT_RADIX__", "2");
   Builder.defineMacro("__DECIMAL_DIG__", "__LDBL_DECIMAL_DIG__");
 

diff  --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index a29ff215d7ea0..82fc57c8f2e88 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -342,6 +342,7 @@ void Preprocessor::RegisterBuiltinMacros() {
   Ident__TIME__ = RegisterBuiltinMacro(*this, "__TIME__");
   Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__");
   Ident_Pragma  = RegisterBuiltinMacro(*this, "_Pragma");
+  Ident__FLT_EVAL_METHOD__ = RegisterBuiltinMacro(*this, "__FLT_EVAL_METHOD__");
 
   // C++ Standing Document Extensions.
   if (getLangOpts().CPlusPlus)
@@ -1574,6 +1575,17 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
     // Surround the string with " and strip the trailing newline.
     OS << '"' << StringRef(Result).drop_back() << '"';
     Tok.setKind(tok::string_literal);
+  } else if (II == Ident__FLT_EVAL_METHOD__) {
+    // __FLT_EVAL_METHOD__ is set to the default value.
+    OS << getTUFPEvalMethod();
+    // __FLT_EVAL_METHOD__ expands to a simple numeric value.
+    Tok.setKind(tok::numeric_constant);
+    if (getLastFPEvalPragmaLocation().isValid()) {
+      // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is altered
+      // by the pragma.
+      Diag(Tok, diag::err_illegal_use_of_flt_eval_macro);
+      Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here);
+    }
   } else if (II == Ident__COUNTER__) {
     // __COUNTER__ expands to a simple numeric value.
     OS << CounterValue++;

diff  --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 27e8501278626..5c6aa0e47635b 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -3028,12 +3028,13 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
 namespace {
 /// Used as the annotation value for tok::annot_pragma_fp.
 struct TokFPAnnotValue {
-  enum FlagKinds { Contract, Reassociate, Exceptions };
+  enum FlagKinds { Contract, Reassociate, Exceptions, EvalMethod };
   enum FlagValues { On, Off, Fast };
 
   llvm::Optional<LangOptions::FPModeKind> ContractValue;
   llvm::Optional<LangOptions::FPModeKind> ReassociateValue;
   llvm::Optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
+  llvm::Optional<LangOptions::FPEvalMethodKind> EvalMethodValue;
 };
 } // end anonymous namespace
 
@@ -3060,6 +3061,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
             .Case("contract", TokFPAnnotValue::Contract)
             .Case("reassociate", TokFPAnnotValue::Reassociate)
             .Case("exceptions", TokFPAnnotValue::Exceptions)
+            .Case("eval_method", TokFPAnnotValue::EvalMethod)
             .Default(None);
     if (!FlagKind) {
       PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
@@ -3074,8 +3076,11 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
       return;
     }
     PP.Lex(Tok);
+    bool isEvalMethodDouble =
+        Tok.is(tok::kw_double) && FlagKind == TokFPAnnotValue::EvalMethod;
 
-    if (Tok.isNot(tok::identifier)) {
+    // Don't diagnose if we have an eval_metod pragma with "double" kind.
+    if (Tok.isNot(tok::identifier) && !isEvalMethodDouble) {
       PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
           << PP.getSpelling(Tok) << OptionInfo->getName()
           << static_cast<int>(*FlagKind);
@@ -3121,6 +3126,19 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
             << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
         return;
       }
+    } else if (FlagKind == TokFPAnnotValue::EvalMethod) {
+      AnnotValue->EvalMethodValue =
+          llvm::StringSwitch<llvm::Optional<LangOptions::FPEvalMethodKind>>(
+              II->getName())
+              .Case("source", LangOptions::FPEvalMethodKind::FEM_Source)
+              .Case("double", LangOptions::FPEvalMethodKind::FEM_Double)
+              .Case("extended", LangOptions::FPEvalMethodKind::FEM_Extended)
+              .Default(llvm::None);
+      if (!AnnotValue->EvalMethodValue) {
+        PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+        return;
+      }
     }
     PP.Lex(Tok);
 
@@ -3223,6 +3241,9 @@ void Parser::HandlePragmaFP() {
   if (AnnotValue->ExceptionsValue)
     Actions.ActOnPragmaFPExceptions(Tok.getLocation(),
                                     *AnnotValue->ExceptionsValue);
+  if (AnnotValue->EvalMethodValue)
+    Actions.ActOnPragmaFPEvalMethod(Tok.getLocation(),
+                                    *AnnotValue->EvalMethodValue);
   ConsumeAnnotationToken();
 }
 

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index ee07775b6346f..cadedf6d98dbd 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1153,6 +1153,16 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
     if (R.isUsable())
       Stmts.push_back(R.get());
   }
+  // Warn the user that using option `-ffp-eval-method=source` on a
+  // 32-bit target and feature `sse` disabled, or using
+  // `pragma clang fp eval_method=source` and feature `sse` disabled, is not
+  // supported.
+  if (!PP.getTargetInfo().supportSourceEvalMethod() &&
+      (PP.getLastFPEvalPragmaLocation().isValid() ||
+       PP.getCurrentFPEvalMethod() ==
+           LangOptions::FPEvalMethodKind::FEM_Source))
+    Diag(Tok.getLocation(),
+         diag::warn_no_support_for_eval_method_source_on_m32);
 
   SourceLocation CloseLoc = Tok.getLocation();
 

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 7b57c8da4e9cc..db3eda622639f 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -242,6 +242,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
   SemaPPCallbackHandler = Callbacks.get();
   PP.addPPCallbacks(std::move(Callbacks));
   SemaPPCallbackHandler->set(*this);
+  if (getLangOpts().getFPEvalMethod() == LangOptions::FEM_UnsetOnCommandLine)
+    // Use setting from TargetInfo.
+    PP.setCurrentFPEvalMethod(SourceLocation(),
+                              ctxt.getTargetInfo().getFPEvalMethod());
+  else
+    // Set initial value of __FLT_EVAL_METHOD__ from the command line.
+    PP.setCurrentFPEvalMethod(SourceLocation(),
+                              getLangOpts().getFPEvalMethod());
+  CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod());
 }
 
 // Anchor Sema's type info to this TU.
@@ -2630,3 +2639,15 @@ const llvm::MapVector<FieldDecl *, Sema::DeleteLocs> &
 Sema::getMismatchingDeleteExpressions() const {
   return DeleteExprs;
 }
+
+Sema::FPFeaturesStateRAII::FPFeaturesStateRAII(Sema &S)
+    : S(S), OldFPFeaturesState(S.CurFPFeatures),
+      OldOverrides(S.FpPragmaStack.CurrentValue),
+      OldEvalMethod(S.PP.getCurrentFPEvalMethod()),
+      OldFPPragmaLocation(S.PP.getLastFPEvalPragmaLocation()) {}
+
+Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() {
+  S.CurFPFeatures = OldFPFeaturesState;
+  S.FpPragmaStack.CurrentValue = OldOverrides;
+  S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod);
+}

diff  --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 38e6e60af90db..d623060fd10cf 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -470,6 +470,27 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
   Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
 }
 
+void Sema::ActOnPragmaFPEvalMethod(SourceLocation Loc,
+                                   LangOptions::FPEvalMethodKind Value) {
+  FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
+  switch (Value) {
+  default:
+    llvm_unreachable("invalid pragma eval_method kind");
+  case LangOptions::FEM_Source:
+    NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Source);
+    break;
+  case LangOptions::FEM_Double:
+    NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Double);
+    break;
+  case LangOptions::FEM_Extended:
+    NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Extended);
+    break;
+  }
+  FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
+  CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
+  PP.setCurrentFPEvalMethod(Loc, Value);
+}
+
 void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
                                    PragmaMsStackAction Action,
                                    PragmaFloatControlKind Value) {

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 22b3f371afe79..88fc89bec629a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -773,6 +773,40 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
   QualType Ty = E->getType();
   assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
 
+  LangOptions::FPEvalMethodKind EvalMethod = CurFPFeatures.getFPEvalMethod();
+  if (EvalMethod != LangOptions::FEM_Source && Ty->isFloatingType() &&
+      (getLangOpts().getFPEvalMethod() !=
+           LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine ||
+       PP.getLastFPEvalPragmaLocation().isValid())) {
+    switch (EvalMethod) {
+    default:
+      llvm_unreachable("Unrecognized float evaluation method");
+      break;
+    case LangOptions::FEM_UnsetOnCommandLine:
+      llvm_unreachable("Float evaluation method should be set by now");
+      break;
+    case LangOptions::FEM_Double:
+      if (Context.getFloatingTypeOrder(Context.DoubleTy, Ty) > 0)
+        // Widen the expression to double.
+        return Ty->isComplexType()
+                   ? ImpCastExprToType(E,
+                                       Context.getComplexType(Context.DoubleTy),
+                                       CK_FloatingComplexCast)
+                   : ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast);
+      break;
+    case LangOptions::FEM_Extended:
+      if (Context.getFloatingTypeOrder(Context.LongDoubleTy, Ty) > 0)
+        // Widen the expression to long double.
+        return Ty->isComplexType()
+                   ? ImpCastExprToType(
+                         E, Context.getComplexType(Context.LongDoubleTy),
+                         CK_FloatingComplexCast)
+                   : ImpCastExprToType(E, Context.LongDoubleTy,
+                                       CK_FloatingCast);
+      break;
+    }
+  }
+
   // Half FP have to be promoted to float unless it is natively supported
   if (Ty->isHalfType() && !getLangOpts().NativeHalfType)
     return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast);

diff  --git a/clang/test/CodeGen/X86/32bit-behavior-no-eval.c b/clang/test/CodeGen/X86/32bit-behavior-no-eval.c
new file mode 100644
index 0000000000000..d040e827ce31c
--- /dev/null
+++ b/clang/test/CodeGen/X86/32bit-behavior-no-eval.c
@@ -0,0 +1,30 @@
+// SSE
+// RUN: %clang_cc1  \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \
+// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s
+
+// NO SSE
+// RUN: %clang_cc1  \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK %s
+
+// NO SSE Fast Math
+// RUN: %clang_cc1  \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -ffast-math -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FM %s
+
+float addit(float a, float b, float c) {
+  // CHECK: load float, float*
+  // CHECK: load float, float*
+  // CHECK: fadd float
+  // CHECK: load float, float*
+  // CHECK: fadd float
+
+  // CHECK-FM: load float, float*
+  // CHECK-FM: load float, float*
+  // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn float
+  // CHECK-FM: load float, float*
+  // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn float
+
+  return a + b + c;
+}

diff  --git a/clang/test/CodeGen/X86/32bit-behavior.c b/clang/test/CodeGen/X86/32bit-behavior.c
new file mode 100644
index 0000000000000..a7e0f008c9f35
--- /dev/null
+++ b/clang/test/CodeGen/X86/32bit-behavior.c
@@ -0,0 +1,109 @@
+// SSE
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=source \
+// RUN: | FileCheck -check-prefix=CHECK-SRC %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=double \
+// RUN: | FileCheck -check-prefix=CHECK-DBL %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \
+// RUN: | FileCheck -check-prefix=CHECK-DBL %s
+
+// SSE Fast Math
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=source \
+// RUN: -ffast-math | FileCheck -check-prefix=CHECK-FM-SRC %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=double \
+// RUN: -ffast-math | FileCheck -check-prefix=CHECK-FM %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature +sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \
+// RUN: -ffast-math | FileCheck -check-prefix=CHECK-FM %s
+
+// NO SSE
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=source  \
+// RUN: | FileCheck -check-prefix=CHECK-SRC %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=double \
+// RUN: | FileCheck -check-prefix=CHECK-DBL %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \
+// RUN: | FileCheck -check-prefix=CHECK-DBL %s
+
+// NO SSE Fast Math
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=source \
+// RUN: -ffast-math | FileCheck -check-prefix=CHECK %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=double \
+// RUN: -ffast-math | FileCheck -check-prefix=CHECK-DBL-FM %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=extended \
+// RUN: -ffast-math | FileCheck -check-prefix=CHECK-DBL-FM %s
+
+float addit(float a, float b, float c) {
+  // CHECK-SRC: load float, float*
+  // CHECK-SRC: load float, float*
+  // CHECK-SRC: fadd float
+  // CHECK-SRC: load float, float*
+  // CHECK-SRC: fadd float
+
+  // CHECK-FM-SRC: load float, float*
+  // CHECK-FM-SRC: load float, float*
+  // CHECK-FM-SRC: fadd reassoc nnan ninf nsz arcp afn float
+  // CHECK-FM-SRC: load float, float*
+  // CHECK-FM-SRC: fadd reassoc nnan ninf nsz arcp afn float
+
+  // CHECK-FM: load float, float*
+  // CHECK-FM: fpext float {{.*}} to double
+  // CHECK-FM: load float, float*
+  // CHECK-FM: fpext float {{.*}} to double
+  // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn double
+  // CHECK-FM: load float, float*
+  // CHECK-FM: fadd reassoc nnan ninf nsz arcp afn double
+  // CHECK-FM: fptrunc double {{.*}} to float
+
+  // CHECK-DBL: load float, float*
+  // CHECK-DBL: fpext float {{.*}} to double
+  // CHECK-DBL: load float, float*
+  // CHECK-DBL: fpext float {{.*}} to double
+  // CHECK-DBL: fadd double
+  // CHECK-DBL: load float, float*
+  // CHECK-DBL: fpext float {{.*}} to double
+  // CHECK-DBL: fadd double
+  // CHECK-DBL: fptrunc double {{.*}} to float
+
+  // CHECK-DBL-FM: load float, float*
+  // CHECK-DBL-FM: fpext float {{.*}} to double
+  // CHECK-DBL-FM: load float, float*
+  // CHECK-DBL-FM: fpext float {{.*}} to double
+  // CHECK-DBL-FM: fadd reassoc nnan ninf nsz arcp afn double
+  // CHECK-DBL-FM: load float, float*
+  // CHECK-DBL-FM: fpext float {{.*}} to double
+  // CHECK-DBL-FM: fadd reassoc nnan ninf nsz arcp afn double
+  // CHECK-DBL-FM: fptrunc double {{.*}} to float
+
+  // CHECK: ret float
+  return a + b + c;
+}

diff  --git a/clang/test/CodeGen/X86/fp-eval-method.c b/clang/test/CodeGen/X86/fp-eval-method.c
new file mode 100644
index 0000000000000..5bfc3701050f5
--- /dev/null
+++ b/clang/test/CodeGen/X86/fp-eval-method.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple i386-unknown-netbsd6 -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefixes=CHECK
+
+// RUN: %clang_cc1 -triple i386-unknown-netbsd7 -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefixes=CHECK-EXT
+
+// RUN: %clang_cc1 -triple i386--linux -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefixes=CHECK-EXT
+
+float f(float x, float y) {
+  // CHECK: define{{.*}} float @f
+  // CHECK: fadd float
+  return 2.0f + x + y;
+}
+
+int getEvalMethod() {
+  // CHECK: ret i32 1
+  // CHECK-EXT: ret i32 2
+  return __FLT_EVAL_METHOD__;
+}

diff  --git a/clang/test/CodeGen/flt_eval_macro.cpp b/clang/test/CodeGen/flt_eval_macro.cpp
new file mode 100644
index 0000000000000..aa7455f0efe0b
--- /dev/null
+++ b/clang/test/CodeGen/flt_eval_macro.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 \
+// RUN: -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-SRC %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \
+// RUN: | FileCheck -check-prefix=CHECK-SRC %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double \
+// RUN: | FileCheck -check-prefixes=CHECK-DBL %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended \
+// RUN: | FileCheck -check-prefixes=CHECK-EXT-FLT %s
+
+// RUN: %clang_cc1 -triple powerpc-unknown-aix -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefix=CHECK-DBL-PPC
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 \
+// RUN: | FileCheck %s -check-prefix=CHECK-EXT-FLT
+
+int getFEM() {
+  // LABEL: define {{.*}}getFEM{{.*}}
+  return __FLT_EVAL_METHOD__;
+  // CHECK-SRC: ret {{.*}} 0
+  // CHECK-DBL: ret {{.*}} 1
+  // CHECK-DBL-PPC: ret {{.*}} 1
+  // CHECK-EXT-FLT: ret {{.*}} 2
+}
+
+float func() {
+  // LABEL: define {{.*}}@_Z4func{{.*}}
+  float X = 100.0f;
+  float Y = -45.3f;
+  float Z = 393.78f;
+  float temp;
+#if __FLT_EVAL_METHOD__ == 0
+  temp = X + Y + Z;
+#elif __FLT_EVAL_METHOD__ == 1
+  temp = X * Y * Z;
+#elif __FLT_EVAL_METHOD__ == 2
+  temp = X * Y - Z;
+#endif
+  // CHECK-SRC: load float, float*
+  // CHECK-SRC: load float, float*
+  // CHECK-SRC: fadd float
+  // CHECK-SRC: load float, float*
+  // CHECK-SRC: fadd float
+
+  // CHECK-DBL: load float, float*
+  // CHECK-DBL: fpext float
+  // CHECK-DBL: load float, float*
+  // CHECK-DBL: fpext float
+  // CHECK-DBL: fmul double
+  // CHECK-DBL: load float, float*
+  // CHECK-DBL: fpext float
+  // CHECK-DBL: fmul double
+  // CHECK-DBL: fptrunc double
+
+  // CHECK-EXT-FLT: load float, float*
+  // CHECK-EXT-FLT: fpext float
+  // CHECK-EXT-FLT: load float, float*
+  // CHECK-EXT-FLT: fpext float
+  // CHECK-EXT-FLT: fmul x86_fp80
+  // CHECK-EXT-FLT: load float, float*
+  // CHECK-EXT-FLT: fpext float
+  // CHECK-EXT-FLT: fsub x86_fp80
+  // CHECK-EXT-FLT: fptrunc x86_fp80
+
+  // CHECK-DBL-PPC: load float, float*
+  // CHECK-DBL-PPC: load float, float*
+  // CHECK-DBL-PPC: fmul float
+  // CHECK-DBL-PPC: load float, float*
+  // CHECK-DBL-PPC: fmul float
+
+  return temp;
+}

diff  --git a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
index ef29d24de1dbc..966eaf6053970 100644
--- a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
+++ b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp
@@ -1,7 +1,53 @@
-// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s
-// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s
-// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -DEXCEPT=1 \
+// RUN: -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-NS %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s \
+// RUN: -check-prefixes=CHECK-DEFAULT,CHECK-CONST-ARGS
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -DFENV_ON=1 \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-FENV %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -DNF128 \
+// RUN: -triple %itanium_abi_triple -O3 -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-O3 %s
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \
+// RUN: | FileCheck %s -check-prefixes=CHECK-SOURCE,CHECK-CONST-ARGS
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=double \
+// RUN: | FileCheck %s -check-prefixes=CHECK-DOUBLE,CHECK-CONST-ARGS
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s -ffp-eval-method=extended \
+// RUN: -mlong-double-80 | FileCheck %s \
+// RUN: -check-prefixes=CHECK-EXTENDED,CHECK-CONST-ARGS
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-linux-gnu -emit-llvm -o - %s -ffp-eval-method=source \
+// RUN: | FileCheck %s -check-prefix=CHECK-SOURCE
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=double | FileCheck %s \
+// RUN: -check-prefix=CHECK-DOUBLE
+
+// RUN: %clang_cc1 -fexperimental-strict-floating-point -triple i386-linux-gnu \
+// RUN: -emit-llvm -o - %s -ffp-eval-method=extended -mlong-double-80 \
+// RUN: | FileCheck %s -check-prefix=CHECK-EXTENDED
+
+// RUN: %clang_cc1 -triple powerpc-unknown-aix -DNF128 -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefix=CHECK-AIX
+
+bool f() {
+  // CHECK: define {{.*}}f{{.*}}
+  return __FLT_EVAL_METHOD__ < 0 &&
+         __FLT_EVAL_METHOD__ == -1;
+  // CHECK: ret {{.*}} true
+}
 
 // Verify float_control(precise, off) enables fast math flags on fp operations.
 float fp_precise_1(float a, float b, float c) {
@@ -229,3 +275,115 @@ float try_lam(float x, unsigned n) {
   result = x + t;
   return result;
 }
+
+float mySub(float x, float y) {
+  // CHECK: define {{.*}}float {{.*}}mySub{{.*}}
+  // CHECK-NS: fsub float
+  // CHECK-SOURCE: fsub float
+  // CHECK-DOUBLE: fpext float
+  // CHECK-DOUBLE: fpext float
+  // CHECK-DOUBLE: fsub double
+  // CHECK-DOUBLE: fptrunc double {{.*}} to float
+  // CHECK-EXTENDED: fpext float
+  // CHECK-EXTENDED: fpext float
+  // CHECK-EXTENDED: fsub double
+  // CHECK-EXTENDED: fptrunc double {{.*}} to float
+  return x - y;
+}
+
+float mySubSource(float x, float y) {
+// CHECK: define {{.*}}float {{.*}}mySubSource{{.*}}
+#pragma clang fp eval_method(source)
+  return x - y;
+  // CHECK: fsub float
+}
+
+float mySubExtended(float x, float y) {
+// CHECK: define {{.*}}float {{.*}}mySubExtended{{.*}}
+#pragma clang fp eval_method(extended)
+  return x - y;
+  // CHECK: fpext float
+  // CHECK: fpext float
+  // CHECK: fsub x86_fp80
+  // CHECK: fptrunc x86_fp80 {{.*}} to float
+  // CHECK-AIX: fsub double
+  // CHECK-AIX: fptrunc double
+}
+
+float mySubDouble(float x, float y) {
+// CHECK: define {{.*}}float {{.*}}mySubDouble{{.*}}
+#pragma clang fp eval_method(double)
+  return x - y;
+  // CHECK: fpext float
+  // CHECK: fpext float
+  // CHECK: fsub double
+  // CHECK: fptrunc double {{.*}} to float
+}
+
+#ifndef NF128
+__float128 mySub128(__float128 x, __float128 y) {
+  // CHECK: define {{.*}}mySub128{{.*}}
+  // Expect no fpext since fp128 is already widest
+  // CHECK: load fp128
+  // CHECK-NEXT: load fp128
+  // CHECK-NEXT: fsub fp128
+  // CHECK-NEXT: ret fp128
+  return x - y;
+}
+#endif
+
+void mySubfp16(__fp16 *res, __fp16 *x, __fp16 *y) {
+  // CHECK: define {{.*}}mySubfp16{{.*}}
+  *res = *x - *y;
+  // CHECK: load half
+  // CHECK-NEXT: load half
+  // CHECK-NEXT: fpext half{{.*}}
+  // CHECK-NEXT: load half
+  // CHECK-NEXT: load half
+  // CHECK-NS: fpext half{{.*}} to float
+  // CHECK-DEFAULT: fpext half{{.*}} to float
+  // CHECK-DOUBLE: fpext half{{.*}} to float
+  // CHECK-EXTENDED: fpext half{{.*}} to float
+  // CHECK-NEXT: fsub
+  // CHECK-NEXT: fptrunc {{.*}}to half
+  // CHECK-NS: fptrunc float {{.*}} to half
+  // CHECK-DOUBLE: fptrunc float {{.*}} to half
+  // CHECK-EXTENDED: fptrunc float {{.*}} to half
+}
+
+float Div(float x, float y, float z) {
+  // CHECK: define{{.*}}float {{.*}}Div{{.*}}
+  // CHECK-CONST-ARGS: fdiv float
+  return x / (y / z);
+}
+
+float DivExtended(float x, float y, float z) {
+// CHECK: define{{.*}}float {{.*}}DivExtended{{.*}}
+#pragma clang fp eval_method(extended)
+  // CHECK-CONST-ARGS: fdiv x86_fp80
+  // CHECK-CONST-ARGS: fptrunc x86_fp80
+  return x / (y / z);
+}
+
+float DivDouble(float x, float y, float z) {
+// CHECK: define{{.*}}float {{.*}}DivDouble{{.*}}
+#pragma clang fp eval_method(double)
+  // CHECK-CONST-ARGS: fdiv double
+  // CHECK-CONST-ARGS: fptrunc double
+  return x / (y / z);
+}
+
+float DivSource(float x, float y, float z) {
+// CHECK: define{{.*}}float {{.*}}DivSource{{.*}}
+#pragma clang fp eval_method(source)
+  // CHECK-CONST-ARGS: fdiv float
+  return x / (y / z);
+}
+
+int main() {
+  float f = Div(4.2f, 1.0f, 3.0f);
+  float fextended = DivExtended(4.2f, 1.0f, 3.0f);
+  float fdouble = DivDouble(4.2f, 1.0f, 3.0f);
+  float fsource = DivSource(4.2f, 1.0f, 3.0f);
+  // CHECK: store float
+}

diff  --git a/clang/test/Preprocessor/flt_eval_macro.cpp b/clang/test/Preprocessor/flt_eval_macro.cpp
new file mode 100644
index 0000000000000..47f2592e261bd
--- /dev/null
+++ b/clang/test/Preprocessor/flt_eval_macro.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -E -dM %s -o - | FileCheck %s -strict-whitespace
+
+#ifdef __FLT_EVAL_METHOD__
+#if __FLT_EVAL_METHOD__ == 3
+#define __GLIBC_FLT_EVAL_METHOD 2
+#else
+#define __GLIBC_FLT_EVAL_METHOD __FLT_EVAL_METHOD__
+#endif
+#elif defined __x86_64__
+#define __GLIBC_FLT_EVAL_METHOD 0
+#else
+#define __GLIBC_FLT_EVAL_METHOD 2
+#endif
+
+#if __GLIBC_FLT_EVAL_METHOD == 0 || __GLIBC_FLT_EVAL_METHOD == 16
+#define Name "One"
+#elif __GLIBC_FLT_EVAL_METHOD == 1
+#define Name "Two"
+#elif __GLIBC_FLT_EVAL_METHOD == 2
+#define Name "Unset on command line"
+#elif __GLIBC_FLT_EVAL_METHOD == 32
+#define Name "Four"
+#elif __GLIBC_FLT_EVAL_METHOD == 33
+#define Name "Five"
+#elif __GLIBC_FLT_EVAL_METHOD == 64
+#define Name "Six"
+#elif __GLIBC_FLT_EVAL_METHOD == 65
+#define Name "Seven"
+#elif __GLIBC_FLT_EVAL_METHOD == 128
+#define Name "Eight"
+#elif __GLIBC_FLT_EVAL_METHOD == 129
+#define Name "Nine"
+#else
+#error "Unknown __GLIBC_FLT_EVAL_METHOD"
+#endif
+
+int foo() {
+  // CHECK: #define Name "Unset on command line"
+  return Name;
+}
+
+#if __FLT_EVAL_METHOD__ == 3
+#define Val "val0"
+#endif
+
+#pragma fp eval_method(double)
+
+#if __FLT_EVAL_METHOD__ == 0
+#define Val "val1"
+#elif __FLT_EVAL_METHOD__ == 1
+#define Val "val2"
+#elif __FLT_EVAL_METHOD__ == 2
+#define Val "val3"
+#endif
+
+int goo() {
+  // CHECK: #define Val "val0"
+  return Name;
+}

diff  --git a/clang/test/Preprocessor/init-aarch64.c b/clang/test/Preprocessor/init-aarch64.c
index f6809d8d9b48f..66cab8b1f8d04 100644
--- a/clang/test/Preprocessor/init-aarch64.c
+++ b/clang/test/Preprocessor/init-aarch64.c
@@ -93,7 +93,6 @@
 // AARCH64-NEXT: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // AARCH64-NEXT: #define __FLT_DIG__ 6
 // AARCH64-NEXT: #define __FLT_EPSILON__ 1.19209290e-7F
-// AARCH64-NEXT: #define __FLT_EVAL_METHOD__ 0
 // AARCH64-NEXT: #define __FLT_HAS_DENORM__ 1
 // AARCH64-NEXT: #define __FLT_HAS_INFINITY__ 1
 // AARCH64-NEXT: #define __FLT_HAS_QUIET_NAN__ 1
@@ -388,7 +387,6 @@
 // AARCH64-DARWIN: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // AARCH64-DARWIN: #define __FLT_DIG__ 6
 // AARCH64-DARWIN: #define __FLT_EPSILON__ 1.19209290e-7F
-// AARCH64-DARWIN: #define __FLT_EVAL_METHOD__ 0
 // AARCH64-DARWIN: #define __FLT_HAS_DENORM__ 1
 // AARCH64-DARWIN: #define __FLT_HAS_INFINITY__ 1
 // AARCH64-DARWIN: #define __FLT_HAS_QUIET_NAN__ 1
@@ -604,7 +602,6 @@
 // AARCH64-MSVC: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // AARCH64-MSVC: #define __FLT_DIG__ 6
 // AARCH64-MSVC: #define __FLT_EPSILON__ 1.19209290e-7F
-// AARCH64-MSVC: #define __FLT_EVAL_METHOD__ 0
 // AARCH64-MSVC: #define __FLT_HAS_DENORM__ 1
 // AARCH64-MSVC: #define __FLT_HAS_INFINITY__ 1
 // AARCH64-MSVC: #define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init-arm.c b/clang/test/Preprocessor/init-arm.c
index 32eb2c513f8b0..2d1503c18560e 100644
--- a/clang/test/Preprocessor/init-arm.c
+++ b/clang/test/Preprocessor/init-arm.c
@@ -35,7 +35,6 @@
 // ARM:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // ARM:#define __FLT_DIG__ 6
 // ARM:#define __FLT_EPSILON__ 1.19209290e-7F
-// ARM:#define __FLT_EVAL_METHOD__ 0
 // ARM:#define __FLT_HAS_DENORM__ 1
 // ARM:#define __FLT_HAS_INFINITY__ 1
 // ARM:#define __FLT_HAS_QUIET_NAN__ 1
@@ -235,7 +234,6 @@
 // ARM-BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // ARM-BE:#define __FLT_DIG__ 6
 // ARM-BE:#define __FLT_EPSILON__ 1.19209290e-7F
-// ARM-BE:#define __FLT_EVAL_METHOD__ 0
 // ARM-BE:#define __FLT_HAS_DENORM__ 1
 // ARM-BE:#define __FLT_HAS_INFINITY__ 1
 // ARM-BE:#define __FLT_HAS_QUIET_NAN__ 1
@@ -428,7 +426,6 @@
 // ARMEABISOFTFP:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // ARMEABISOFTFP:#define __FLT_DIG__ 6
 // ARMEABISOFTFP:#define __FLT_EPSILON__ 1.19209290e-7F
-// ARMEABISOFTFP:#define __FLT_EVAL_METHOD__ 0
 // ARMEABISOFTFP:#define __FLT_HAS_DENORM__ 1
 // ARMEABISOFTFP:#define __FLT_HAS_INFINITY__ 1
 // ARMEABISOFTFP:#define __FLT_HAS_QUIET_NAN__ 1
@@ -623,7 +620,6 @@
 // ARMEABIHARDFP:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // ARMEABIHARDFP:#define __FLT_DIG__ 6
 // ARMEABIHARDFP:#define __FLT_EPSILON__ 1.19209290e-7F
-// ARMEABIHARDFP:#define __FLT_EVAL_METHOD__ 0
 // ARMEABIHARDFP:#define __FLT_HAS_DENORM__ 1
 // ARMEABIHARDFP:#define __FLT_HAS_INFINITY__ 1
 // ARMEABIHARDFP:#define __FLT_HAS_QUIET_NAN__ 1
@@ -821,7 +817,6 @@
 // ARM-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // ARM-NETBSD:#define __FLT_DIG__ 6
 // ARM-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F
-// ARM-NETBSD:#define __FLT_EVAL_METHOD__ 0
 // ARM-NETBSD:#define __FLT_HAS_DENORM__ 1
 // ARM-NETBSD:#define __FLT_HAS_INFINITY__ 1
 // ARM-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init-mips.c b/clang/test/Preprocessor/init-mips.c
index d76396aa35c91..a07cee64e6848 100644
--- a/clang/test/Preprocessor/init-mips.c
+++ b/clang/test/Preprocessor/init-mips.c
@@ -37,7 +37,6 @@
 // MIPS32BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // MIPS32BE:#define __FLT_DIG__ 6
 // MIPS32BE:#define __FLT_EPSILON__ 1.19209290e-7F
-// MIPS32BE:#define __FLT_EVAL_METHOD__ 0
 // MIPS32BE:#define __FLT_HAS_DENORM__ 1
 // MIPS32BE:#define __FLT_HAS_INFINITY__ 1
 // MIPS32BE:#define __FLT_HAS_QUIET_NAN__ 1
@@ -247,7 +246,6 @@
 // MIPS32EL:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // MIPS32EL:#define __FLT_DIG__ 6
 // MIPS32EL:#define __FLT_EPSILON__ 1.19209290e-7F
-// MIPS32EL:#define __FLT_EVAL_METHOD__ 0
 // MIPS32EL:#define __FLT_HAS_DENORM__ 1
 // MIPS32EL:#define __FLT_HAS_INFINITY__ 1
 // MIPS32EL:#define __FLT_HAS_QUIET_NAN__ 1
@@ -467,7 +465,6 @@
 // MIPSN32BE: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // MIPSN32BE: #define __FLT_DIG__ 6
 // MIPSN32BE: #define __FLT_EPSILON__ 1.19209290e-7F
-// MIPSN32BE: #define __FLT_EVAL_METHOD__ 0
 // MIPSN32BE: #define __FLT_HAS_DENORM__ 1
 // MIPSN32BE: #define __FLT_HAS_INFINITY__ 1
 // MIPSN32BE: #define __FLT_HAS_QUIET_NAN__ 1
@@ -774,7 +771,6 @@
 // MIPSN32EL: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // MIPSN32EL: #define __FLT_DIG__ 6
 // MIPSN32EL: #define __FLT_EPSILON__ 1.19209290e-7F
-// MIPSN32EL: #define __FLT_EVAL_METHOD__ 0
 // MIPSN32EL: #define __FLT_HAS_DENORM__ 1
 // MIPSN32EL: #define __FLT_HAS_INFINITY__ 1
 // MIPSN32EL: #define __FLT_HAS_QUIET_NAN__ 1
@@ -1074,7 +1070,6 @@
 // MIPS64BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // MIPS64BE:#define __FLT_DIG__ 6
 // MIPS64BE:#define __FLT_EPSILON__ 1.19209290e-7F
-// MIPS64BE:#define __FLT_EVAL_METHOD__ 0
 // MIPS64BE:#define __FLT_HAS_DENORM__ 1
 // MIPS64BE:#define __FLT_HAS_INFINITY__ 1
 // MIPS64BE:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1284,7 +1279,6 @@
 // MIPS64EL:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // MIPS64EL:#define __FLT_DIG__ 6
 // MIPS64EL:#define __FLT_EPSILON__ 1.19209290e-7F
-// MIPS64EL:#define __FLT_EVAL_METHOD__ 0
 // MIPS64EL:#define __FLT_HAS_DENORM__ 1
 // MIPS64EL:#define __FLT_HAS_INFINITY__ 1
 // MIPS64EL:#define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init-ppc.c b/clang/test/Preprocessor/init-ppc.c
index 611b16dfb8f7e..45c8a5e53ad4f 100644
--- a/clang/test/Preprocessor/init-ppc.c
+++ b/clang/test/Preprocessor/init-ppc.c
@@ -30,7 +30,6 @@
 // PPC603E:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC603E:#define __FLT_DIG__ 6
 // PPC603E:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC603E:#define __FLT_EVAL_METHOD__ 0
 // PPC603E:#define __FLT_HAS_DENORM__ 1
 // PPC603E:#define __FLT_HAS_INFINITY__ 1
 // PPC603E:#define __FLT_HAS_QUIET_NAN__ 1
@@ -224,7 +223,6 @@
 // PPC:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC:#define __FLT_DIG__ 6
 // PPC:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC:#define __FLT_EVAL_METHOD__ 0
 // PPC:#define __FLT_HAS_DENORM__ 1
 // PPC:#define __FLT_HAS_INFINITY__ 1
 // PPC:#define __FLT_HAS_QUIET_NAN__ 1
@@ -425,7 +423,6 @@
 // PPC-AIX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC-AIX:#define __FLT_DIG__ 6
 // PPC-AIX:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC-AIX:#define __FLT_EVAL_METHOD__ 1
 // PPC-AIX:#define __FLT_HAS_DENORM__ 1
 // PPC-AIX:#define __FLT_HAS_INFINITY__ 1
 // PPC-AIX:#define __FLT_HAS_QUIET_NAN__ 1
@@ -798,7 +795,6 @@
 // PPC-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC-LINUX:#define __FLT_DIG__ 6
 // PPC-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC-LINUX:#define __FLT_EVAL_METHOD__ 0
 // PPC-LINUX:#define __FLT_HAS_DENORM__ 1
 // PPC-LINUX:#define __FLT_HAS_INFINITY__ 1
 // PPC-LINUX:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1006,7 +1002,6 @@
 // PPC-DARWIN:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC-DARWIN:#define __FLT_DIG__ 6
 // PPC-DARWIN:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC-DARWIN:#define __FLT_EVAL_METHOD__ 0
 // PPC-DARWIN:#define __FLT_HAS_DENORM__ 1
 // PPC-DARWIN:#define __FLT_HAS_INFINITY__ 1
 // PPC-DARWIN:#define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init-ppc64.c b/clang/test/Preprocessor/init-ppc64.c
index 7a9525228c3b6..f0ccd1638c04d 100644
--- a/clang/test/Preprocessor/init-ppc64.c
+++ b/clang/test/Preprocessor/init-ppc64.c
@@ -35,7 +35,6 @@
 // PPC64:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC64:#define __FLT_DIG__ 6
 // PPC64:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC64:#define __FLT_EVAL_METHOD__ 0
 // PPC64:#define __FLT_HAS_DENORM__ 1
 // PPC64:#define __FLT_HAS_INFINITY__ 1
 // PPC64:#define __FLT_HAS_QUIET_NAN__ 1
@@ -240,7 +239,6 @@
 // PPC64LE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC64LE:#define __FLT_DIG__ 6
 // PPC64LE:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC64LE:#define __FLT_EVAL_METHOD__ 0
 // PPC64LE:#define __FLT_HAS_DENORM__ 1
 // PPC64LE:#define __FLT_HAS_INFINITY__ 1
 // PPC64LE:#define __FLT_HAS_QUIET_NAN__ 1
@@ -703,7 +701,6 @@
 // PPC64-AIX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC64-AIX:#define __FLT_DIG__ 6
 // PPC64-AIX:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC64-AIX:#define __FLT_EVAL_METHOD__ 1
 // PPC64-AIX:#define __FLT_HAS_DENORM__ 1
 // PPC64-AIX:#define __FLT_HAS_INFINITY__ 1
 // PPC64-AIX:#define __FLT_HAS_QUIET_NAN__ 1
@@ -902,7 +899,6 @@
 // PPC64-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PPC64-LINUX:#define __FLT_DIG__ 6
 // PPC64-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F
-// PPC64-LINUX:#define __FLT_EVAL_METHOD__ 0
 // PPC64-LINUX:#define __FLT_HAS_DENORM__ 1
 // PPC64-LINUX:#define __FLT_HAS_INFINITY__ 1
 // PPC64-LINUX:#define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init-s390x.c b/clang/test/Preprocessor/init-s390x.c
index b0e45b5348ce9..6c646527f50f7 100644
--- a/clang/test/Preprocessor/init-s390x.c
+++ b/clang/test/Preprocessor/init-s390x.c
@@ -23,7 +23,6 @@
 // S390X:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // S390X:#define __FLT_DIG__ 6
 // S390X:#define __FLT_EPSILON__ 1.19209290e-7F
-// S390X:#define __FLT_EVAL_METHOD__ 0
 // S390X:#define __FLT_HAS_DENORM__ 1
 // S390X:#define __FLT_HAS_INFINITY__ 1
 // S390X:#define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init-v7k-compat.c b/clang/test/Preprocessor/init-v7k-compat.c
index 482c7ad6ff687..ff5d4bbdea53a 100644
--- a/clang/test/Preprocessor/init-v7k-compat.c
+++ b/clang/test/Preprocessor/init-v7k-compat.c
@@ -28,7 +28,6 @@
 // CHECK: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // CHECK: #define __FLT_DIG__ 6
 // CHECK: #define __FLT_EPSILON__ 1.19209290e-7F
-// CHECK: #define __FLT_EVAL_METHOD__ 0
 // CHECK: #define __FLT_HAS_DENORM__ 1
 // CHECK: #define __FLT_HAS_INFINITY__ 1
 // CHECK: #define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init-x86.c b/clang/test/Preprocessor/init-x86.c
index 527cd39508889..aa2e05ec807c7 100644
--- a/clang/test/Preprocessor/init-x86.c
+++ b/clang/test/Preprocessor/init-x86.c
@@ -24,7 +24,6 @@
 // I386:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // I386:#define __FLT_DIG__ 6
 // I386:#define __FLT_EPSILON__ 1.19209290e-7F
-// I386:#define __FLT_EVAL_METHOD__ 2
 // I386:#define __FLT_HAS_DENORM__ 1
 // I386:#define __FLT_HAS_INFINITY__ 1
 // I386:#define __FLT_HAS_QUIET_NAN__ 1
@@ -213,7 +212,6 @@
 // I386-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // I386-LINUX:#define __FLT_DIG__ 6
 // I386-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F
-// I386-LINUX:#define __FLT_EVAL_METHOD__ 0
 // I386-LINUX:#define __FLT_HAS_DENORM__ 1
 // I386-LINUX:#define __FLT_HAS_INFINITY__ 1
 // I386-LINUX:#define __FLT_HAS_QUIET_NAN__ 1
@@ -416,7 +414,6 @@
 // I386-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // I386-NETBSD:#define __FLT_DIG__ 6
 // I386-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F
-// I386-NETBSD:#define __FLT_EVAL_METHOD__ 2
 // I386-NETBSD:#define __FLT_HAS_DENORM__ 1
 // I386-NETBSD:#define __FLT_HAS_INFINITY__ 1
 // I386-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1
@@ -590,13 +587,6 @@
 // I386-NETBSD:#define __i386__ 1
 // I386-NETBSD:#define i386 1
 
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd -target-feature +sse2 < /dev/null | FileCheck -match-full-lines -check-prefix I386-NETBSD-SSE %s
-// I386-NETBSD-SSE:#define __FLT_EVAL_METHOD__ 0
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd6  < /dev/null | FileCheck -match-full-lines -check-prefix I386-NETBSD6 %s
-// I386-NETBSD6:#define __FLT_EVAL_METHOD__ 1
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-netbsd6 -target-feature +sse2 < /dev/null | FileCheck -match-full-lines -check-prefix I386-NETBSD6-SSE %s
-// I386-NETBSD6-SSE:#define __FLT_EVAL_METHOD__ 1
-
 // RUN: %clang_cc1 -E -dM -triple=i686-pc-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix I386-DECLSPEC %s
 // RUN: %clang_cc1 -E -dM -fms-extensions -triple=i686-pc-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix I386-DECLSPEC %s
 // RUN: %clang_cc1 -E -dM -triple=i686-unknown-cygwin < /dev/null | FileCheck -match-full-lines -check-prefix I386-DECLSPEC %s
@@ -631,7 +621,6 @@
 // X86_64:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // X86_64:#define __FLT_DIG__ 6
 // X86_64:#define __FLT_EPSILON__ 1.19209290e-7F
-// X86_64:#define __FLT_EVAL_METHOD__ 0
 // X86_64:#define __FLT_HAS_DENORM__ 1
 // X86_64:#define __FLT_HAS_INFINITY__ 1
 // X86_64:#define __FLT_HAS_QUIET_NAN__ 1
@@ -839,7 +828,6 @@
 // X32:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // X32:#define __FLT_DIG__ 6
 // X32:#define __FLT_EPSILON__ 1.19209290e-7F
-// X32:#define __FLT_EVAL_METHOD__ 0
 // X32:#define __FLT_HAS_DENORM__ 1
 // X32:#define __FLT_HAS_INFINITY__ 1
 // X32:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1046,7 +1034,6 @@
 // X86_64-CLOUDABI:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // X86_64-CLOUDABI:#define __FLT_DIG__ 6
 // X86_64-CLOUDABI:#define __FLT_EPSILON__ 1.19209290e-7F
-// X86_64-CLOUDABI:#define __FLT_EVAL_METHOD__ 0
 // X86_64-CLOUDABI:#define __FLT_HAS_DENORM__ 1
 // X86_64-CLOUDABI:#define __FLT_HAS_INFINITY__ 1
 // X86_64-CLOUDABI:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1341,7 +1328,6 @@
 // X86_64-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // X86_64-LINUX:#define __FLT_DIG__ 6
 // X86_64-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F
-// X86_64-LINUX:#define __FLT_EVAL_METHOD__ 0
 // X86_64-LINUX:#define __FLT_HAS_DENORM__ 1
 // X86_64-LINUX:#define __FLT_HAS_INFINITY__ 1
 // X86_64-LINUX:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1554,7 +1540,6 @@
 // X86_64-NETBSD:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // X86_64-NETBSD:#define __FLT_DIG__ 6
 // X86_64-NETBSD:#define __FLT_EPSILON__ 1.19209290e-7F
-// X86_64-NETBSD:#define __FLT_EVAL_METHOD__ 0
 // X86_64-NETBSD:#define __FLT_HAS_DENORM__ 1
 // X86_64-NETBSD:#define __FLT_HAS_INFINITY__ 1
 // X86_64-NETBSD:#define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c
index dd645bf6003ce..a08e503570723 100644
--- a/clang/test/Preprocessor/init.c
+++ b/clang/test/Preprocessor/init.c
@@ -325,7 +325,6 @@
 // MSP430:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // MSP430:#define __FLT_DIG__ 6
 // MSP430:#define __FLT_EPSILON__ 1.19209290e-7F
-// MSP430:#define __FLT_EVAL_METHOD__ 0
 // MSP430:#define __FLT_HAS_DENORM__ 1
 // MSP430:#define __FLT_HAS_INFINITY__ 1
 // MSP430:#define __FLT_HAS_QUIET_NAN__ 1
@@ -513,7 +512,6 @@
 // NVPTX32:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // NVPTX32:#define __FLT_DIG__ 6
 // NVPTX32:#define __FLT_EPSILON__ 1.19209290e-7F
-// NVPTX32:#define __FLT_EVAL_METHOD__ 0
 // NVPTX32:#define __FLT_HAS_DENORM__ 1
 // NVPTX32:#define __FLT_HAS_INFINITY__ 1
 // NVPTX32:#define __FLT_HAS_QUIET_NAN__ 1
@@ -702,7 +700,6 @@
 // NVPTX64:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // NVPTX64:#define __FLT_DIG__ 6
 // NVPTX64:#define __FLT_EPSILON__ 1.19209290e-7F
-// NVPTX64:#define __FLT_EVAL_METHOD__ 0
 // NVPTX64:#define __FLT_HAS_DENORM__ 1
 // NVPTX64:#define __FLT_HAS_INFINITY__ 1
 // NVPTX64:#define __FLT_HAS_QUIET_NAN__ 1
@@ -906,7 +903,6 @@
 // SPARC:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // SPARC:#define __FLT_DIG__ 6
 // SPARC:#define __FLT_EPSILON__ 1.19209290e-7F
-// SPARC:#define __FLT_EVAL_METHOD__ 0
 // SPARC:#define __FLT_HAS_DENORM__ 1
 // SPARC:#define __FLT_HAS_INFINITY__ 1
 // SPARC:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1107,7 +1103,6 @@
 // TCE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // TCE:#define __FLT_DIG__ 6
 // TCE:#define __FLT_EPSILON__ 1.19209290e-7F
-// TCE:#define __FLT_EVAL_METHOD__ 0
 // TCE:#define __FLT_HAS_DENORM__ 1
 // TCE:#define __FLT_HAS_INFINITY__ 1
 // TCE:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1274,7 +1269,6 @@
 // PS4:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // PS4:#define __FLT_DIG__ 6
 // PS4:#define __FLT_EPSILON__ 1.19209290e-7F
-// PS4:#define __FLT_EVAL_METHOD__ 0
 // PS4:#define __FLT_HAS_DENORM__ 1
 // PS4:#define __FLT_HAS_INFINITY__ 1
 // PS4:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1576,7 +1570,6 @@
 // WEBASSEMBLY-NEXT:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // WEBASSEMBLY-NEXT:#define __FLT_DIG__ 6
 // WEBASSEMBLY-NEXT:#define __FLT_EPSILON__ 1.19209290e-7F
-// WEBASSEMBLY-NEXT:#define __FLT_EVAL_METHOD__ 0
 // WEBASSEMBLY-NEXT:#define __FLT_HAS_DENORM__ 1
 // WEBASSEMBLY-NEXT:#define __FLT_HAS_INFINITY__ 1
 // WEBASSEMBLY-NEXT:#define __FLT_HAS_QUIET_NAN__ 1
@@ -1946,7 +1939,6 @@
 // AVR:#define __FLT_DENORM_MIN__ 1.40129846e-45F
 // AVR:#define __FLT_DIG__ 6
 // AVR:#define __FLT_EPSILON__ 1.19209290e-7F
-// AVR:#define __FLT_EVAL_METHOD__ 0
 // AVR:#define __FLT_HAS_DENORM__ 1
 // AVR:#define __FLT_HAS_INFINITY__ 1
 // AVR:#define __FLT_HAS_QUIET_NAN__ 1
@@ -2083,7 +2075,6 @@
 // AVR:#define __WCHAR_TYPE__ int
 // AVR:#define __WINT_TYPE__ int
 
-
 // RUN: %clang_cc1 -E -dM -ffreestanding \
 // RUN:    -triple i686-windows-msvc -fms-compatibility -x c++ < /dev/null \
 // RUN:  | FileCheck -match-full-lines -check-prefix MSVC-X32 %s
@@ -2229,7 +2220,6 @@
 // RISCV32: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // RISCV32: #define __FLT_DIG__ 6
 // RISCV32: #define __FLT_EPSILON__ 1.19209290e-7F
-// RISCV32: #define __FLT_EVAL_METHOD__ 0
 // RISCV32: #define __FLT_HAS_DENORM__ 1
 // RISCV32: #define __FLT_HAS_INFINITY__ 1
 // RISCV32: #define __FLT_HAS_QUIET_NAN__ 1
@@ -2437,7 +2427,6 @@
 // RISCV64: #define __FLT_DENORM_MIN__ 1.40129846e-45F
 // RISCV64: #define __FLT_DIG__ 6
 // RISCV64: #define __FLT_EPSILON__ 1.19209290e-7F
-// RISCV64: #define __FLT_EVAL_METHOD__ 0
 // RISCV64: #define __FLT_HAS_DENORM__ 1
 // RISCV64: #define __FLT_HAS_INFINITY__ 1
 // RISCV64: #define __FLT_HAS_QUIET_NAN__ 1

diff  --git a/clang/test/Sema/fp-eval-pragma.cpp b/clang/test/Sema/fp-eval-pragma.cpp
new file mode 100644
index 0000000000000..42d88fd438e81
--- /dev/null
+++ b/clang/test/Sema/fp-eval-pragma.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify %s
+//
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify %s \
+// RUN: -ffp-eval-method=source
+//
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify %s \
+// RUN: -ffp-eval-method=double
+
+extern "C" int printf(const char *, ...);
+
+void foo1() {
+  printf("FP: %d\n", __FLT_EVAL_METHOD__);
+}
+
+void apply_pragma() {
+  // expected-note at +1{{#pragma entered here}}
+#pragma clang fp eval_method(double)
+  // expected-error at +1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}}
+  printf("FP: %d\n", __FLT_EVAL_METHOD__);
+}
+
+int foo2() {
+  apply_pragma();
+  return 0;
+}
+
+void foo() {
+  auto a = __FLT_EVAL_METHOD__;
+  {
+    // expected-note at +1{{#pragma entered here}}
+#pragma clang fp eval_method(double)
+    // expected-error at +1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}}
+    auto b = __FLT_EVAL_METHOD__;
+  }
+  auto c = __FLT_EVAL_METHOD__;
+}
+
+void func() {
+  {
+    {
+#pragma clang fp eval_method(source)
+    }
+    int i = __FLT_EVAL_METHOD__; // ok, not in a scope changed by the pragma
+  }
+  {
+    // expected-note at +1{{#pragma entered here}}
+#pragma clang fp eval_method(source)
+    // expected-error at +1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}}
+    int i = __FLT_EVAL_METHOD__;
+  }
+}
+
+float G;
+
+int f(float x, float y, float z) {
+  G = x * y + z;
+  return __FLT_EVAL_METHOD__;
+}
+
+int foo(int flag, float x, float y, float z) {
+  if (flag) {
+    // expected-note at +1{{#pragma entered here}}
+#pragma clang fp eval_method(double)
+    G = x + y + z;
+    // expected-error at +1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}}
+    return __FLT_EVAL_METHOD__;
+  } else {
+    // expected-note at +1{{#pragma entered here}}
+#pragma clang fp eval_method(extended)
+    G = x + y + z;
+    // expected-error at +1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}}
+    return __FLT_EVAL_METHOD__;
+  }
+}
+
+#if __FLT_EVAL_METHOD__ == 1
+#endif
+#pragma clang fp eval_method(source)
+
+// expected-note at +1{{#pragma entered here}}
+#pragma clang fp eval_method(double)
+// expected-error at +1{{'__FLT_EVAL_METHOD__' cannot be expanded inside a scope containing '#pragma clang fp eval_method'}}
+#if __FLT_EVAL_METHOD__ == 1
+#endif

diff  --git a/clang/test/Sema/x86-eval-method.c b/clang/test/Sema/x86-eval-method.c
new file mode 100644
index 0000000000000..90f2fefc511c0
--- /dev/null
+++ b/clang/test/Sema/x86-eval-method.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 -target-feature -sse \
+// RUN: -emit-llvm -ffp-eval-method=source  -o - -verify=warn %s
+// 
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple i386-pc-windows -target-cpu pentium4 \
+// RUN: -emit-llvm -ffp-eval-method=source  -o - -verify=no-warn %s
+
+// no-warn-no-diagnostics
+
+float add1(float a, float b, float c) {
+  return a + b + c;
+} // warn-warning{{Setting FPEvalMethod to source on a 32bit target, with no SSE is not supported.}}
+
+float add2(float a, float b, float c) {
+#pragma clang fp eval_method(source)
+  return a + b + c;
+} // warn-warning{{Setting FPEvalMethod to source on a 32bit target, with no SSE is not supported.}}

diff  --git a/clang/test/Sema/x86_64-eval-method.c b/clang/test/Sema/x86_64-eval-method.c
new file mode 100644
index 0000000000000..728423dd1b65b
--- /dev/null
+++ b/clang/test/Sema/x86_64-eval-method.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -target-feature -sse -emit-llvm -o - -verify %s
+//
+// RUN: %clang_cc1 -fexperimental-strict-floating-point \
+// RUN: -triple x86_64-linux-gnu -emit-llvm -o - -verify=no-warn %s
+
+// no-warn-no-diagnostics
+
+float add2(float a, float b, float c) {
+#pragma clang fp eval_method(source)
+  return a + b + c;
+} // expected-warning{{Setting FPEvalMethod to source on a 32bit target, with no SSE is not supported.}}


        


More information about the cfe-commits mailing list